roojs-bootstrap.js
[roojs1] / roojs-bootstrap-debug.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
17  * @cfg {string} dataId cutomer id
18  * @cfg {string} name Specifies name attribute
19  * @cfg {string} tooltip  Text for the tooltip
20  * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar -  getHeaderChildContainer)
21  * 
22  * @constructor
23  * Do not use directly - it does not do anything..
24  * @param {Object} config The config object
25  */
26
27
28
29 Roo.bootstrap.Component = function(config){
30     Roo.bootstrap.Component.superclass.constructor.call(this, config);
31        
32     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         this.setValue(this.originalValue);
11786         this.clearInvalid();
11787         this.lastData = false;
11788         if (this.view) {
11789             this.view.clearSelections();
11790         }
11791     },
11792     // private
11793     findRecord : function(prop, value){
11794         var record;
11795         if(this.store.getCount() > 0){
11796             this.store.each(function(r){
11797                 if(r.data[prop] == value){
11798                     record = r;
11799                     return false;
11800                 }
11801                 return true;
11802             });
11803         }
11804         return record;
11805     },
11806     
11807     getName: function()
11808     {
11809         // returns hidden if it's set..
11810         if (!this.rendered) {return ''};
11811         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
11812         
11813     },
11814     // private
11815     onViewMove : function(e, t){
11816         this.inKeyMode = false;
11817     },
11818
11819     // private
11820     onViewOver : function(e, t){
11821         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11822             return;
11823         }
11824         var item = this.view.findItemFromChild(t);
11825         
11826         if(item){
11827             var index = this.view.indexOf(item);
11828             this.select(index, false);
11829         }
11830     },
11831
11832     // private
11833     onViewClick : function(view, doFocus, el, e)
11834     {
11835         var index = this.view.getSelectedIndexes()[0];
11836         
11837         var r = this.store.getAt(index);
11838         
11839         if(this.tickable){
11840             
11841             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11842                 return;
11843             }
11844             
11845             var rm = false;
11846             var _this = this;
11847             
11848             Roo.each(this.tickItems, function(v,k){
11849                 
11850                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11851                     _this.tickItems.splice(k, 1);
11852                     
11853                     if(typeof(e) == 'undefined' && view == false){
11854                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11855                     }
11856                     
11857                     rm = true;
11858                     return;
11859                 }
11860             });
11861             
11862             if(rm){
11863                 return;
11864             }
11865             
11866             this.tickItems.push(r.data);
11867             
11868             if(typeof(e) == 'undefined' && view == false){
11869                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11870             }
11871                     
11872             return;
11873         }
11874         
11875         if(r){
11876             this.onSelect(r, index);
11877         }
11878         if(doFocus !== false && !this.blockFocus){
11879             this.inputEl().focus();
11880         }
11881     },
11882
11883     // private
11884     restrictHeight : function(){
11885         //this.innerList.dom.style.height = '';
11886         //var inner = this.innerList.dom;
11887         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11888         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11889         //this.list.beginUpdate();
11890         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11891         this.list.alignTo(this.inputEl(), this.listAlign);
11892         this.list.alignTo(this.inputEl(), this.listAlign);
11893         //this.list.endUpdate();
11894     },
11895
11896     // private
11897     onEmptyResults : function(){
11898         
11899         if(this.tickable && this.editable){
11900             this.restrictHeight();
11901             return;
11902         }
11903         
11904         this.collapse();
11905     },
11906
11907     /**
11908      * Returns true if the dropdown list is expanded, else false.
11909      */
11910     isExpanded : function(){
11911         return this.list.isVisible();
11912     },
11913
11914     /**
11915      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11916      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11917      * @param {String} value The data value of the item to select
11918      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11919      * selected item if it is not currently in view (defaults to true)
11920      * @return {Boolean} True if the value matched an item in the list, else false
11921      */
11922     selectByValue : function(v, scrollIntoView){
11923         if(v !== undefined && v !== null){
11924             var r = this.findRecord(this.valueField || this.displayField, v);
11925             if(r){
11926                 this.select(this.store.indexOf(r), scrollIntoView);
11927                 return true;
11928             }
11929         }
11930         return false;
11931     },
11932
11933     /**
11934      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11935      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11936      * @param {Number} index The zero-based index of the list item to select
11937      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11938      * selected item if it is not currently in view (defaults to true)
11939      */
11940     select : function(index, scrollIntoView){
11941         this.selectedIndex = index;
11942         this.view.select(index);
11943         if(scrollIntoView !== false){
11944             var el = this.view.getNode(index);
11945             /*
11946              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
11947              */
11948             if(el){
11949                 this.list.scrollChildIntoView(el, false);
11950             }
11951         }
11952     },
11953
11954     // private
11955     selectNext : function(){
11956         var ct = this.store.getCount();
11957         if(ct > 0){
11958             if(this.selectedIndex == -1){
11959                 this.select(0);
11960             }else if(this.selectedIndex < ct-1){
11961                 this.select(this.selectedIndex+1);
11962             }
11963         }
11964     },
11965
11966     // private
11967     selectPrev : function(){
11968         var ct = this.store.getCount();
11969         if(ct > 0){
11970             if(this.selectedIndex == -1){
11971                 this.select(0);
11972             }else if(this.selectedIndex != 0){
11973                 this.select(this.selectedIndex-1);
11974             }
11975         }
11976     },
11977
11978     // private
11979     onKeyUp : function(e){
11980         if(this.editable !== false && !e.isSpecialKey()){
11981             this.lastKey = e.getKey();
11982             this.dqTask.delay(this.queryDelay);
11983         }
11984     },
11985
11986     // private
11987     validateBlur : function(){
11988         return !this.list || !this.list.isVisible();   
11989     },
11990
11991     // private
11992     initQuery : function(){
11993         
11994         var v = this.getRawValue();
11995         
11996         if(this.tickable && this.editable){
11997             v = this.tickableInputEl().getValue();
11998         }
11999         
12000         this.doQuery(v);
12001     },
12002
12003     // private
12004     doForce : function(){
12005         if(this.inputEl().dom.value.length > 0){
12006             this.inputEl().dom.value =
12007                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12008              
12009         }
12010     },
12011
12012     /**
12013      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
12014      * query allowing the query action to be canceled if needed.
12015      * @param {String} query The SQL query to execute
12016      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12017      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
12018      * saved in the current store (defaults to false)
12019      */
12020     doQuery : function(q, forceAll){
12021         
12022         if(q === undefined || q === null){
12023             q = '';
12024         }
12025         var qe = {
12026             query: q,
12027             forceAll: forceAll,
12028             combo: this,
12029             cancel:false
12030         };
12031         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12032             return false;
12033         }
12034         q = qe.query;
12035         
12036         forceAll = qe.forceAll;
12037         if(forceAll === true || (q.length >= this.minChars)){
12038             
12039             this.hasQuery = true;
12040             
12041             if(this.lastQuery != q || this.alwaysQuery){
12042                 this.lastQuery = q;
12043                 if(this.mode == 'local'){
12044                     this.selectedIndex = -1;
12045                     if(forceAll){
12046                         this.store.clearFilter();
12047                     }else{
12048                         this.store.filter(this.displayField, q);
12049                     }
12050                     this.onLoad();
12051                 }else{
12052                     
12053                     this.store.baseParams[this.queryParam] = q;
12054                     
12055                     var options = {params : this.getParams(q)};
12056                     
12057                     if(this.loadNext){
12058                         options.add = true;
12059                         options.params.start = this.page * this.pageSize;
12060                     }
12061                     
12062                     this.store.load(options);
12063                     
12064                     /*
12065                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
12066                      *  we should expand the list on onLoad
12067                      *  so command out it
12068                      */
12069 //                    this.expand();
12070                 }
12071             }else{
12072                 this.selectedIndex = -1;
12073                 this.onLoad();   
12074             }
12075         }
12076         
12077         this.loadNext = false;
12078     },
12079
12080     // private
12081     getParams : function(q){
12082         var p = {};
12083         //p[this.queryParam] = q;
12084         
12085         if(this.pageSize){
12086             p.start = 0;
12087             p.limit = this.pageSize;
12088         }
12089         return p;
12090     },
12091
12092     /**
12093      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12094      */
12095     collapse : function(){
12096         if(!this.isExpanded()){
12097             return;
12098         }
12099         
12100         this.list.hide();
12101         
12102         if(this.tickable){
12103             this.hasFocus = false;
12104             this.okBtn.hide();
12105             this.cancelBtn.hide();
12106             this.trigger.show();
12107             
12108             if(this.editable){
12109                 this.tickableInputEl().dom.value = '';
12110                 this.tickableInputEl().blur();
12111             }
12112             
12113         }
12114         
12115         Roo.get(document).un('mousedown', this.collapseIf, this);
12116         Roo.get(document).un('mousewheel', this.collapseIf, this);
12117         if (!this.editable) {
12118             Roo.get(document).un('keydown', this.listKeyPress, this);
12119         }
12120         this.fireEvent('collapse', this);
12121     },
12122
12123     // private
12124     collapseIf : function(e){
12125         var in_combo  = e.within(this.el);
12126         var in_list =  e.within(this.list);
12127         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12128         
12129         if (in_combo || in_list || is_list) {
12130             //e.stopPropagation();
12131             return;
12132         }
12133         
12134         if(this.tickable){
12135             this.onTickableFooterButtonClick(e, false, false);
12136         }
12137
12138         this.collapse();
12139         
12140     },
12141
12142     /**
12143      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12144      */
12145     expand : function(){
12146        
12147         if(this.isExpanded() || !this.hasFocus){
12148             return;
12149         }
12150         
12151         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12152         this.list.setWidth(lw);
12153         
12154         
12155          Roo.log('expand');
12156         
12157         this.list.show();
12158         
12159         this.restrictHeight();
12160         
12161         if(this.tickable){
12162             
12163             this.tickItems = Roo.apply([], this.item);
12164             
12165             this.okBtn.show();
12166             this.cancelBtn.show();
12167             this.trigger.hide();
12168             
12169             if(this.editable){
12170                 this.tickableInputEl().focus();
12171             }
12172             
12173         }
12174         
12175         Roo.get(document).on('mousedown', this.collapseIf, this);
12176         Roo.get(document).on('mousewheel', this.collapseIf, this);
12177         if (!this.editable) {
12178             Roo.get(document).on('keydown', this.listKeyPress, this);
12179         }
12180         
12181         this.fireEvent('expand', this);
12182     },
12183
12184     // private
12185     // Implements the default empty TriggerField.onTriggerClick function
12186     onTriggerClick : function(e)
12187     {
12188         Roo.log('trigger click');
12189         
12190         if(this.disabled || !this.triggerList){
12191             return;
12192         }
12193         
12194         this.page = 0;
12195         this.loadNext = false;
12196         
12197         if(this.isExpanded()){
12198             this.collapse();
12199             if (!this.blockFocus) {
12200                 this.inputEl().focus();
12201             }
12202             
12203         }else {
12204             this.hasFocus = true;
12205             if(this.triggerAction == 'all') {
12206                 this.doQuery(this.allQuery, true);
12207             } else {
12208                 this.doQuery(this.getRawValue());
12209             }
12210             if (!this.blockFocus) {
12211                 this.inputEl().focus();
12212             }
12213         }
12214     },
12215     
12216     onTickableTriggerClick : function(e)
12217     {
12218         if(this.disabled){
12219             return;
12220         }
12221         
12222         this.page = 0;
12223         this.loadNext = false;
12224         this.hasFocus = true;
12225         
12226         if(this.triggerAction == 'all') {
12227             this.doQuery(this.allQuery, true);
12228         } else {
12229             this.doQuery(this.getRawValue());
12230         }
12231     },
12232     
12233     onSearchFieldClick : function(e)
12234     {
12235         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12236             this.onTickableFooterButtonClick(e, false, false);
12237             return;
12238         }
12239         
12240         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12241             return;
12242         }
12243         
12244         this.page = 0;
12245         this.loadNext = false;
12246         this.hasFocus = true;
12247         
12248         if(this.triggerAction == 'all') {
12249             this.doQuery(this.allQuery, true);
12250         } else {
12251             this.doQuery(this.getRawValue());
12252         }
12253     },
12254     
12255     listKeyPress : function(e)
12256     {
12257         //Roo.log('listkeypress');
12258         // scroll to first matching element based on key pres..
12259         if (e.isSpecialKey()) {
12260             return false;
12261         }
12262         var k = String.fromCharCode(e.getKey()).toUpperCase();
12263         //Roo.log(k);
12264         var match  = false;
12265         var csel = this.view.getSelectedNodes();
12266         var cselitem = false;
12267         if (csel.length) {
12268             var ix = this.view.indexOf(csel[0]);
12269             cselitem  = this.store.getAt(ix);
12270             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12271                 cselitem = false;
12272             }
12273             
12274         }
12275         
12276         this.store.each(function(v) { 
12277             if (cselitem) {
12278                 // start at existing selection.
12279                 if (cselitem.id == v.id) {
12280                     cselitem = false;
12281                 }
12282                 return true;
12283             }
12284                 
12285             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12286                 match = this.store.indexOf(v);
12287                 return false;
12288             }
12289             return true;
12290         }, this);
12291         
12292         if (match === false) {
12293             return true; // no more action?
12294         }
12295         // scroll to?
12296         this.view.select(match);
12297         var sn = Roo.get(this.view.getSelectedNodes()[0])
12298         sn.scrollIntoView(sn.dom.parentNode, false);
12299     },
12300     
12301     onViewScroll : function(e, t){
12302         
12303         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){
12304             return;
12305         }
12306         
12307         this.hasQuery = true;
12308         
12309         this.loading = this.list.select('.loading', true).first();
12310         
12311         if(this.loading === null){
12312             this.list.createChild({
12313                 tag: 'div',
12314                 cls: 'loading select2-more-results select2-active',
12315                 html: 'Loading more results...'
12316             })
12317             
12318             this.loading = this.list.select('.loading', true).first();
12319             
12320             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12321             
12322             this.loading.hide();
12323         }
12324         
12325         this.loading.show();
12326         
12327         var _combo = this;
12328         
12329         this.page++;
12330         this.loadNext = true;
12331         
12332         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12333         
12334         return;
12335     },
12336     
12337     addItem : function(o)
12338     {   
12339         var dv = ''; // display value
12340         
12341         if (this.displayField) {
12342             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12343         } else {
12344             // this is an error condition!!!
12345             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
12346         }
12347         
12348         if(!dv.length){
12349             return;
12350         }
12351         
12352         var choice = this.choices.createChild({
12353             tag: 'li',
12354             cls: 'select2-search-choice',
12355             cn: [
12356                 {
12357                     tag: 'div',
12358                     html: dv
12359                 },
12360                 {
12361                     tag: 'a',
12362                     href: '#',
12363                     cls: 'select2-search-choice-close',
12364                     tabindex: '-1'
12365                 }
12366             ]
12367             
12368         }, this.searchField);
12369         
12370         var close = choice.select('a.select2-search-choice-close', true).first()
12371         
12372         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12373         
12374         this.item.push(o);
12375         
12376         this.lastData = o;
12377         
12378         this.syncValue();
12379         
12380         this.inputEl().dom.value = '';
12381         
12382         this.validate();
12383     },
12384     
12385     onRemoveItem : function(e, _self, o)
12386     {
12387         e.preventDefault();
12388         
12389         this.lastItem = Roo.apply([], this.item);
12390         
12391         var index = this.item.indexOf(o.data) * 1;
12392         
12393         if( index < 0){
12394             Roo.log('not this item?!');
12395             return;
12396         }
12397         
12398         this.item.splice(index, 1);
12399         o.item.remove();
12400         
12401         this.syncValue();
12402         
12403         this.fireEvent('remove', this, e);
12404         
12405         this.validate();
12406         
12407     },
12408     
12409     syncValue : function()
12410     {
12411         if(!this.item.length){
12412             this.clearValue();
12413             return;
12414         }
12415             
12416         var value = [];
12417         var _this = this;
12418         Roo.each(this.item, function(i){
12419             if(_this.valueField){
12420                 value.push(i[_this.valueField]);
12421                 return;
12422             }
12423
12424             value.push(i);
12425         });
12426
12427         this.value = value.join(',');
12428
12429         if(this.hiddenField){
12430             this.hiddenField.dom.value = this.value;
12431         }
12432     },
12433     
12434     clearItem : function()
12435     {
12436         if(!this.multiple){
12437             return;
12438         }
12439         
12440         this.item = [];
12441         
12442         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12443            c.remove();
12444         });
12445         
12446         this.syncValue();
12447         
12448         this.validate();
12449     },
12450     
12451     inputEl: function ()
12452     {
12453         if(this.tickable){
12454             return this.searchField;
12455         }
12456         return this.el.select('input.form-control',true).first();
12457     },
12458     
12459     
12460     onTickableFooterButtonClick : function(e, btn, el)
12461     {
12462         e.preventDefault();
12463         
12464         this.lastItem = Roo.apply([], this.item);
12465         
12466         if(btn && btn.name == 'cancel'){
12467             this.tickItems = Roo.apply([], this.item);
12468             this.collapse();
12469             return;
12470         }
12471         
12472         this.clearItem();
12473         
12474         var _this = this;
12475         
12476         Roo.each(this.tickItems, function(o){
12477             _this.addItem(o);
12478         });
12479         
12480         this.collapse();
12481         
12482     },
12483     
12484     validate : function()
12485     {
12486         var v = this.getRawValue();
12487         
12488         if(this.multiple){
12489             v = this.getValue();
12490         }
12491         
12492         if(this.disabled || this.allowBlank || v.length){
12493             this.markValid();
12494             return true;
12495         }
12496         
12497         this.markInvalid();
12498         return false;
12499     },
12500     
12501     tickableInputEl : function()
12502     {
12503         if(!this.tickable || !this.editable){
12504             return this.inputEl();
12505         }
12506         
12507         return this.inputEl().select('.select2-search-field-input', true).first();
12508     }
12509     
12510     
12511
12512     /** 
12513     * @cfg {Boolean} grow 
12514     * @hide 
12515     */
12516     /** 
12517     * @cfg {Number} growMin 
12518     * @hide 
12519     */
12520     /** 
12521     * @cfg {Number} growMax 
12522     * @hide 
12523     */
12524     /**
12525      * @hide
12526      * @method autoSize
12527      */
12528 });
12529 /*
12530  * Based on:
12531  * Ext JS Library 1.1.1
12532  * Copyright(c) 2006-2007, Ext JS, LLC.
12533  *
12534  * Originally Released Under LGPL - original licence link has changed is not relivant.
12535  *
12536  * Fork - LGPL
12537  * <script type="text/javascript">
12538  */
12539
12540 /**
12541  * @class Roo.View
12542  * @extends Roo.util.Observable
12543  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
12544  * This class also supports single and multi selection modes. <br>
12545  * Create a data model bound view:
12546  <pre><code>
12547  var store = new Roo.data.Store(...);
12548
12549  var view = new Roo.View({
12550     el : "my-element",
12551     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
12552  
12553     singleSelect: true,
12554     selectedClass: "ydataview-selected",
12555     store: store
12556  });
12557
12558  // listen for node click?
12559  view.on("click", function(vw, index, node, e){
12560  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12561  });
12562
12563  // load XML data
12564  dataModel.load("foobar.xml");
12565  </code></pre>
12566  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12567  * <br><br>
12568  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12569  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12570  * 
12571  * Note: old style constructor is still suported (container, template, config)
12572  * 
12573  * @constructor
12574  * Create a new View
12575  * @param {Object} config The config object
12576  * 
12577  */
12578 Roo.View = function(config, depreciated_tpl, depreciated_config){
12579     
12580     this.parent = false;
12581     
12582     if (typeof(depreciated_tpl) == 'undefined') {
12583         // new way.. - universal constructor.
12584         Roo.apply(this, config);
12585         this.el  = Roo.get(this.el);
12586     } else {
12587         // old format..
12588         this.el  = Roo.get(config);
12589         this.tpl = depreciated_tpl;
12590         Roo.apply(this, depreciated_config);
12591     }
12592     this.wrapEl  = this.el.wrap().wrap();
12593     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12594     
12595     
12596     if(typeof(this.tpl) == "string"){
12597         this.tpl = new Roo.Template(this.tpl);
12598     } else {
12599         // support xtype ctors..
12600         this.tpl = new Roo.factory(this.tpl, Roo);
12601     }
12602     
12603     
12604     this.tpl.compile();
12605     
12606     /** @private */
12607     this.addEvents({
12608         /**
12609          * @event beforeclick
12610          * Fires before a click is processed. Returns false to cancel the default action.
12611          * @param {Roo.View} this
12612          * @param {Number} index The index of the target node
12613          * @param {HTMLElement} node The target node
12614          * @param {Roo.EventObject} e The raw event object
12615          */
12616             "beforeclick" : true,
12617         /**
12618          * @event click
12619          * Fires when a template node is clicked.
12620          * @param {Roo.View} this
12621          * @param {Number} index The index of the target node
12622          * @param {HTMLElement} node The target node
12623          * @param {Roo.EventObject} e The raw event object
12624          */
12625             "click" : true,
12626         /**
12627          * @event dblclick
12628          * Fires when a template node is double clicked.
12629          * @param {Roo.View} this
12630          * @param {Number} index The index of the target node
12631          * @param {HTMLElement} node The target node
12632          * @param {Roo.EventObject} e The raw event object
12633          */
12634             "dblclick" : true,
12635         /**
12636          * @event contextmenu
12637          * Fires when a template node is right clicked.
12638          * @param {Roo.View} this
12639          * @param {Number} index The index of the target node
12640          * @param {HTMLElement} node The target node
12641          * @param {Roo.EventObject} e The raw event object
12642          */
12643             "contextmenu" : true,
12644         /**
12645          * @event selectionchange
12646          * Fires when the selected nodes change.
12647          * @param {Roo.View} this
12648          * @param {Array} selections Array of the selected nodes
12649          */
12650             "selectionchange" : true,
12651     
12652         /**
12653          * @event beforeselect
12654          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12655          * @param {Roo.View} this
12656          * @param {HTMLElement} node The node to be selected
12657          * @param {Array} selections Array of currently selected nodes
12658          */
12659             "beforeselect" : true,
12660         /**
12661          * @event preparedata
12662          * Fires on every row to render, to allow you to change the data.
12663          * @param {Roo.View} this
12664          * @param {Object} data to be rendered (change this)
12665          */
12666           "preparedata" : true
12667           
12668           
12669         });
12670
12671
12672
12673     this.el.on({
12674         "click": this.onClick,
12675         "dblclick": this.onDblClick,
12676         "contextmenu": this.onContextMenu,
12677         scope:this
12678     });
12679
12680     this.selections = [];
12681     this.nodes = [];
12682     this.cmp = new Roo.CompositeElementLite([]);
12683     if(this.store){
12684         this.store = Roo.factory(this.store, Roo.data);
12685         this.setStore(this.store, true);
12686     }
12687     
12688     if ( this.footer && this.footer.xtype) {
12689            
12690          var fctr = this.wrapEl.appendChild(document.createElement("div"));
12691         
12692         this.footer.dataSource = this.store
12693         this.footer.container = fctr;
12694         this.footer = Roo.factory(this.footer, Roo);
12695         fctr.insertFirst(this.el);
12696         
12697         // this is a bit insane - as the paging toolbar seems to detach the el..
12698 //        dom.parentNode.parentNode.parentNode
12699          // they get detached?
12700     }
12701     
12702     
12703     Roo.View.superclass.constructor.call(this);
12704     
12705     
12706 };
12707
12708 Roo.extend(Roo.View, Roo.util.Observable, {
12709     
12710      /**
12711      * @cfg {Roo.data.Store} store Data store to load data from.
12712      */
12713     store : false,
12714     
12715     /**
12716      * @cfg {String|Roo.Element} el The container element.
12717      */
12718     el : '',
12719     
12720     /**
12721      * @cfg {String|Roo.Template} tpl The template used by this View 
12722      */
12723     tpl : false,
12724     /**
12725      * @cfg {String} dataName the named area of the template to use as the data area
12726      *                          Works with domtemplates roo-name="name"
12727      */
12728     dataName: false,
12729     /**
12730      * @cfg {String} selectedClass The css class to add to selected nodes
12731      */
12732     selectedClass : "x-view-selected",
12733      /**
12734      * @cfg {String} emptyText The empty text to show when nothing is loaded.
12735      */
12736     emptyText : "",
12737     
12738     /**
12739      * @cfg {String} text to display on mask (default Loading)
12740      */
12741     mask : false,
12742     /**
12743      * @cfg {Boolean} multiSelect Allow multiple selection
12744      */
12745     multiSelect : false,
12746     /**
12747      * @cfg {Boolean} singleSelect Allow single selection
12748      */
12749     singleSelect:  false,
12750     
12751     /**
12752      * @cfg {Boolean} toggleSelect - selecting 
12753      */
12754     toggleSelect : false,
12755     
12756     /**
12757      * @cfg {Boolean} tickable - selecting 
12758      */
12759     tickable : false,
12760     
12761     /**
12762      * Returns the element this view is bound to.
12763      * @return {Roo.Element}
12764      */
12765     getEl : function(){
12766         return this.wrapEl;
12767     },
12768     
12769     
12770
12771     /**
12772      * Refreshes the view. - called by datachanged on the store. - do not call directly.
12773      */
12774     refresh : function(){
12775         //Roo.log('refresh');
12776         var t = this.tpl;
12777         
12778         // if we are using something like 'domtemplate', then
12779         // the what gets used is:
12780         // t.applySubtemplate(NAME, data, wrapping data..)
12781         // the outer template then get' applied with
12782         //     the store 'extra data'
12783         // and the body get's added to the
12784         //      roo-name="data" node?
12785         //      <span class='roo-tpl-{name}'></span> ?????
12786         
12787         
12788         
12789         this.clearSelections();
12790         this.el.update("");
12791         var html = [];
12792         var records = this.store.getRange();
12793         if(records.length < 1) {
12794             
12795             // is this valid??  = should it render a template??
12796             
12797             this.el.update(this.emptyText);
12798             return;
12799         }
12800         var el = this.el;
12801         if (this.dataName) {
12802             this.el.update(t.apply(this.store.meta)); //????
12803             el = this.el.child('.roo-tpl-' + this.dataName);
12804         }
12805         
12806         for(var i = 0, len = records.length; i < len; i++){
12807             var data = this.prepareData(records[i].data, i, records[i]);
12808             this.fireEvent("preparedata", this, data, i, records[i]);
12809             
12810             var d = Roo.apply({}, data);
12811             
12812             if(this.tickable){
12813                 Roo.apply(d, {'roo-id' : Roo.id()});
12814                 
12815                 var _this = this;
12816             
12817                 Roo.each(this.parent.item, function(item){
12818                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12819                         return;
12820                     }
12821                     Roo.apply(d, {'roo-data-checked' : 'checked'});
12822                 });
12823             }
12824             
12825             html[html.length] = Roo.util.Format.trim(
12826                 this.dataName ?
12827                     t.applySubtemplate(this.dataName, d, this.store.meta) :
12828                     t.apply(d)
12829             );
12830         }
12831         
12832         
12833         
12834         el.update(html.join(""));
12835         this.nodes = el.dom.childNodes;
12836         this.updateIndexes(0);
12837     },
12838     
12839
12840     /**
12841      * Function to override to reformat the data that is sent to
12842      * the template for each node.
12843      * DEPRICATED - use the preparedata event handler.
12844      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12845      * a JSON object for an UpdateManager bound view).
12846      */
12847     prepareData : function(data, index, record)
12848     {
12849         this.fireEvent("preparedata", this, data, index, record);
12850         return data;
12851     },
12852
12853     onUpdate : function(ds, record){
12854         // Roo.log('on update');   
12855         this.clearSelections();
12856         var index = this.store.indexOf(record);
12857         var n = this.nodes[index];
12858         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12859         n.parentNode.removeChild(n);
12860         this.updateIndexes(index, index);
12861     },
12862
12863     
12864     
12865 // --------- FIXME     
12866     onAdd : function(ds, records, index)
12867     {
12868         //Roo.log(['on Add', ds, records, index] );        
12869         this.clearSelections();
12870         if(this.nodes.length == 0){
12871             this.refresh();
12872             return;
12873         }
12874         var n = this.nodes[index];
12875         for(var i = 0, len = records.length; i < len; i++){
12876             var d = this.prepareData(records[i].data, i, records[i]);
12877             if(n){
12878                 this.tpl.insertBefore(n, d);
12879             }else{
12880                 
12881                 this.tpl.append(this.el, d);
12882             }
12883         }
12884         this.updateIndexes(index);
12885     },
12886
12887     onRemove : function(ds, record, index){
12888        // Roo.log('onRemove');
12889         this.clearSelections();
12890         var el = this.dataName  ?
12891             this.el.child('.roo-tpl-' + this.dataName) :
12892             this.el; 
12893         
12894         el.dom.removeChild(this.nodes[index]);
12895         this.updateIndexes(index);
12896     },
12897
12898     /**
12899      * Refresh an individual node.
12900      * @param {Number} index
12901      */
12902     refreshNode : function(index){
12903         this.onUpdate(this.store, this.store.getAt(index));
12904     },
12905
12906     updateIndexes : function(startIndex, endIndex){
12907         var ns = this.nodes;
12908         startIndex = startIndex || 0;
12909         endIndex = endIndex || ns.length - 1;
12910         for(var i = startIndex; i <= endIndex; i++){
12911             ns[i].nodeIndex = i;
12912         }
12913     },
12914
12915     /**
12916      * Changes the data store this view uses and refresh the view.
12917      * @param {Store} store
12918      */
12919     setStore : function(store, initial){
12920         if(!initial && this.store){
12921             this.store.un("datachanged", this.refresh);
12922             this.store.un("add", this.onAdd);
12923             this.store.un("remove", this.onRemove);
12924             this.store.un("update", this.onUpdate);
12925             this.store.un("clear", this.refresh);
12926             this.store.un("beforeload", this.onBeforeLoad);
12927             this.store.un("load", this.onLoad);
12928             this.store.un("loadexception", this.onLoad);
12929         }
12930         if(store){
12931           
12932             store.on("datachanged", this.refresh, this);
12933             store.on("add", this.onAdd, this);
12934             store.on("remove", this.onRemove, this);
12935             store.on("update", this.onUpdate, this);
12936             store.on("clear", this.refresh, this);
12937             store.on("beforeload", this.onBeforeLoad, this);
12938             store.on("load", this.onLoad, this);
12939             store.on("loadexception", this.onLoad, this);
12940         }
12941         
12942         if(store){
12943             this.refresh();
12944         }
12945     },
12946     /**
12947      * onbeforeLoad - masks the loading area.
12948      *
12949      */
12950     onBeforeLoad : function(store,opts)
12951     {
12952          //Roo.log('onBeforeLoad');   
12953         if (!opts.add) {
12954             this.el.update("");
12955         }
12956         this.el.mask(this.mask ? this.mask : "Loading" ); 
12957     },
12958     onLoad : function ()
12959     {
12960         this.el.unmask();
12961     },
12962     
12963
12964     /**
12965      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12966      * @param {HTMLElement} node
12967      * @return {HTMLElement} The template node
12968      */
12969     findItemFromChild : function(node){
12970         var el = this.dataName  ?
12971             this.el.child('.roo-tpl-' + this.dataName,true) :
12972             this.el.dom; 
12973         
12974         if(!node || node.parentNode == el){
12975                     return node;
12976             }
12977             var p = node.parentNode;
12978             while(p && p != el){
12979             if(p.parentNode == el){
12980                 return p;
12981             }
12982             p = p.parentNode;
12983         }
12984             return null;
12985     },
12986
12987     /** @ignore */
12988     onClick : function(e){
12989         var item = this.findItemFromChild(e.getTarget());
12990         if(item){
12991             var index = this.indexOf(item);
12992             if(this.onItemClick(item, index, e) !== false){
12993                 this.fireEvent("click", this, index, item, e);
12994             }
12995         }else{
12996             this.clearSelections();
12997         }
12998     },
12999
13000     /** @ignore */
13001     onContextMenu : function(e){
13002         var item = this.findItemFromChild(e.getTarget());
13003         if(item){
13004             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13005         }
13006     },
13007
13008     /** @ignore */
13009     onDblClick : function(e){
13010         var item = this.findItemFromChild(e.getTarget());
13011         if(item){
13012             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13013         }
13014     },
13015
13016     onItemClick : function(item, index, e)
13017     {
13018         if(this.fireEvent("beforeclick", this, index, item, e) === false){
13019             return false;
13020         }
13021         if (this.toggleSelect) {
13022             var m = this.isSelected(item) ? 'unselect' : 'select';
13023             //Roo.log(m);
13024             var _t = this;
13025             _t[m](item, true, false);
13026             return true;
13027         }
13028         if(this.multiSelect || this.singleSelect){
13029             if(this.multiSelect && e.shiftKey && this.lastSelection){
13030                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13031             }else{
13032                 this.select(item, this.multiSelect && e.ctrlKey);
13033                 this.lastSelection = item;
13034             }
13035             
13036             if(!this.tickable){
13037                 e.preventDefault();
13038             }
13039             
13040         }
13041         return true;
13042     },
13043
13044     /**
13045      * Get the number of selected nodes.
13046      * @return {Number}
13047      */
13048     getSelectionCount : function(){
13049         return this.selections.length;
13050     },
13051
13052     /**
13053      * Get the currently selected nodes.
13054      * @return {Array} An array of HTMLElements
13055      */
13056     getSelectedNodes : function(){
13057         return this.selections;
13058     },
13059
13060     /**
13061      * Get the indexes of the selected nodes.
13062      * @return {Array}
13063      */
13064     getSelectedIndexes : function(){
13065         var indexes = [], s = this.selections;
13066         for(var i = 0, len = s.length; i < len; i++){
13067             indexes.push(s[i].nodeIndex);
13068         }
13069         return indexes;
13070     },
13071
13072     /**
13073      * Clear all selections
13074      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13075      */
13076     clearSelections : function(suppressEvent){
13077         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13078             this.cmp.elements = this.selections;
13079             this.cmp.removeClass(this.selectedClass);
13080             this.selections = [];
13081             if(!suppressEvent){
13082                 this.fireEvent("selectionchange", this, this.selections);
13083             }
13084         }
13085     },
13086
13087     /**
13088      * Returns true if the passed node is selected
13089      * @param {HTMLElement/Number} node The node or node index
13090      * @return {Boolean}
13091      */
13092     isSelected : function(node){
13093         var s = this.selections;
13094         if(s.length < 1){
13095             return false;
13096         }
13097         node = this.getNode(node);
13098         return s.indexOf(node) !== -1;
13099     },
13100
13101     /**
13102      * Selects nodes.
13103      * @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
13104      * @param {Boolean} keepExisting (optional) true to keep existing selections
13105      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13106      */
13107     select : function(nodeInfo, keepExisting, suppressEvent){
13108         if(nodeInfo instanceof Array){
13109             if(!keepExisting){
13110                 this.clearSelections(true);
13111             }
13112             for(var i = 0, len = nodeInfo.length; i < len; i++){
13113                 this.select(nodeInfo[i], true, true);
13114             }
13115             return;
13116         } 
13117         var node = this.getNode(nodeInfo);
13118         if(!node || this.isSelected(node)){
13119             return; // already selected.
13120         }
13121         if(!keepExisting){
13122             this.clearSelections(true);
13123         }
13124         
13125         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13126             Roo.fly(node).addClass(this.selectedClass);
13127             this.selections.push(node);
13128             if(!suppressEvent){
13129                 this.fireEvent("selectionchange", this, this.selections);
13130             }
13131         }
13132         
13133         
13134     },
13135       /**
13136      * Unselects nodes.
13137      * @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
13138      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13139      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13140      */
13141     unselect : function(nodeInfo, keepExisting, suppressEvent)
13142     {
13143         if(nodeInfo instanceof Array){
13144             Roo.each(this.selections, function(s) {
13145                 this.unselect(s, nodeInfo);
13146             }, this);
13147             return;
13148         }
13149         var node = this.getNode(nodeInfo);
13150         if(!node || !this.isSelected(node)){
13151             //Roo.log("not selected");
13152             return; // not selected.
13153         }
13154         // fireevent???
13155         var ns = [];
13156         Roo.each(this.selections, function(s) {
13157             if (s == node ) {
13158                 Roo.fly(node).removeClass(this.selectedClass);
13159
13160                 return;
13161             }
13162             ns.push(s);
13163         },this);
13164         
13165         this.selections= ns;
13166         this.fireEvent("selectionchange", this, this.selections);
13167     },
13168
13169     /**
13170      * Gets a template node.
13171      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13172      * @return {HTMLElement} The node or null if it wasn't found
13173      */
13174     getNode : function(nodeInfo){
13175         if(typeof nodeInfo == "string"){
13176             return document.getElementById(nodeInfo);
13177         }else if(typeof nodeInfo == "number"){
13178             return this.nodes[nodeInfo];
13179         }
13180         return nodeInfo;
13181     },
13182
13183     /**
13184      * Gets a range template nodes.
13185      * @param {Number} startIndex
13186      * @param {Number} endIndex
13187      * @return {Array} An array of nodes
13188      */
13189     getNodes : function(start, end){
13190         var ns = this.nodes;
13191         start = start || 0;
13192         end = typeof end == "undefined" ? ns.length - 1 : end;
13193         var nodes = [];
13194         if(start <= end){
13195             for(var i = start; i <= end; i++){
13196                 nodes.push(ns[i]);
13197             }
13198         } else{
13199             for(var i = start; i >= end; i--){
13200                 nodes.push(ns[i]);
13201             }
13202         }
13203         return nodes;
13204     },
13205
13206     /**
13207      * Finds the index of the passed node
13208      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13209      * @return {Number} The index of the node or -1
13210      */
13211     indexOf : function(node){
13212         node = this.getNode(node);
13213         if(typeof node.nodeIndex == "number"){
13214             return node.nodeIndex;
13215         }
13216         var ns = this.nodes;
13217         for(var i = 0, len = ns.length; i < len; i++){
13218             if(ns[i] == node){
13219                 return i;
13220             }
13221         }
13222         return -1;
13223     }
13224 });
13225 /*
13226  * - LGPL
13227  *
13228  * based on jquery fullcalendar
13229  * 
13230  */
13231
13232 Roo.bootstrap = Roo.bootstrap || {};
13233 /**
13234  * @class Roo.bootstrap.Calendar
13235  * @extends Roo.bootstrap.Component
13236  * Bootstrap Calendar class
13237  * @cfg {Boolean} loadMask (true|false) default false
13238  * @cfg {Object} header generate the user specific header of the calendar, default false
13239
13240  * @constructor
13241  * Create a new Container
13242  * @param {Object} config The config object
13243  */
13244
13245
13246
13247 Roo.bootstrap.Calendar = function(config){
13248     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13249      this.addEvents({
13250         /**
13251              * @event select
13252              * Fires when a date is selected
13253              * @param {DatePicker} this
13254              * @param {Date} date The selected date
13255              */
13256         'select': true,
13257         /**
13258              * @event monthchange
13259              * Fires when the displayed month changes 
13260              * @param {DatePicker} this
13261              * @param {Date} date The selected month
13262              */
13263         'monthchange': true,
13264         /**
13265              * @event evententer
13266              * Fires when mouse over an event
13267              * @param {Calendar} this
13268              * @param {event} Event
13269              */
13270         'evententer': true,
13271         /**
13272              * @event eventleave
13273              * Fires when the mouse leaves an
13274              * @param {Calendar} this
13275              * @param {event}
13276              */
13277         'eventleave': true,
13278         /**
13279              * @event eventclick
13280              * Fires when the mouse click an
13281              * @param {Calendar} this
13282              * @param {event}
13283              */
13284         'eventclick': true
13285         
13286     });
13287
13288 };
13289
13290 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
13291     
13292      /**
13293      * @cfg {Number} startDay
13294      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13295      */
13296     startDay : 0,
13297     
13298     loadMask : false,
13299     
13300     header : false,
13301       
13302     getAutoCreate : function(){
13303         
13304         
13305         var fc_button = function(name, corner, style, content ) {
13306             return Roo.apply({},{
13307                 tag : 'span',
13308                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
13309                          (corner.length ?
13310                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13311                             ''
13312                         ),
13313                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13314                 unselectable: 'on'
13315             });
13316         };
13317         
13318         var header = {};
13319         
13320         if(!this.header){
13321             header = {
13322                 tag : 'table',
13323                 cls : 'fc-header',
13324                 style : 'width:100%',
13325                 cn : [
13326                     {
13327                         tag: 'tr',
13328                         cn : [
13329                             {
13330                                 tag : 'td',
13331                                 cls : 'fc-header-left',
13332                                 cn : [
13333                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
13334                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
13335                                     { tag: 'span', cls: 'fc-header-space' },
13336                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
13337
13338
13339                                 ]
13340                             },
13341
13342                             {
13343                                 tag : 'td',
13344                                 cls : 'fc-header-center',
13345                                 cn : [
13346                                     {
13347                                         tag: 'span',
13348                                         cls: 'fc-header-title',
13349                                         cn : {
13350                                             tag: 'H2',
13351                                             html : 'month / year'
13352                                         }
13353                                     }
13354
13355                                 ]
13356                             },
13357                             {
13358                                 tag : 'td',
13359                                 cls : 'fc-header-right',
13360                                 cn : [
13361                               /*      fc_button('month', 'left', '', 'month' ),
13362                                     fc_button('week', '', '', 'week' ),
13363                                     fc_button('day', 'right', '', 'day' )
13364                                 */    
13365
13366                                 ]
13367                             }
13368
13369                         ]
13370                     }
13371                 ]
13372             };
13373         }
13374         
13375         header = this.header;
13376         
13377        
13378         var cal_heads = function() {
13379             var ret = [];
13380             // fixme - handle this.
13381             
13382             for (var i =0; i < Date.dayNames.length; i++) {
13383                 var d = Date.dayNames[i];
13384                 ret.push({
13385                     tag: 'th',
13386                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13387                     html : d.substring(0,3)
13388                 });
13389                 
13390             }
13391             ret[0].cls += ' fc-first';
13392             ret[6].cls += ' fc-last';
13393             return ret;
13394         };
13395         var cal_cell = function(n) {
13396             return  {
13397                 tag: 'td',
13398                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13399                 cn : [
13400                     {
13401                         cn : [
13402                             {
13403                                 cls: 'fc-day-number',
13404                                 html: 'D'
13405                             },
13406                             {
13407                                 cls: 'fc-day-content',
13408                              
13409                                 cn : [
13410                                      {
13411                                         style: 'position: relative;' // height: 17px;
13412                                     }
13413                                 ]
13414                             }
13415                             
13416                             
13417                         ]
13418                     }
13419                 ]
13420                 
13421             }
13422         };
13423         var cal_rows = function() {
13424             
13425             var ret = [];
13426             for (var r = 0; r < 6; r++) {
13427                 var row= {
13428                     tag : 'tr',
13429                     cls : 'fc-week',
13430                     cn : []
13431                 };
13432                 
13433                 for (var i =0; i < Date.dayNames.length; i++) {
13434                     var d = Date.dayNames[i];
13435                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13436
13437                 }
13438                 row.cn[0].cls+=' fc-first';
13439                 row.cn[0].cn[0].style = 'min-height:90px';
13440                 row.cn[6].cls+=' fc-last';
13441                 ret.push(row);
13442                 
13443             }
13444             ret[0].cls += ' fc-first';
13445             ret[4].cls += ' fc-prev-last';
13446             ret[5].cls += ' fc-last';
13447             return ret;
13448             
13449         };
13450         
13451         var cal_table = {
13452             tag: 'table',
13453             cls: 'fc-border-separate',
13454             style : 'width:100%',
13455             cellspacing  : 0,
13456             cn : [
13457                 { 
13458                     tag: 'thead',
13459                     cn : [
13460                         { 
13461                             tag: 'tr',
13462                             cls : 'fc-first fc-last',
13463                             cn : cal_heads()
13464                         }
13465                     ]
13466                 },
13467                 { 
13468                     tag: 'tbody',
13469                     cn : cal_rows()
13470                 }
13471                   
13472             ]
13473         };
13474          
13475          var cfg = {
13476             cls : 'fc fc-ltr',
13477             cn : [
13478                 header,
13479                 {
13480                     cls : 'fc-content',
13481                     style : "position: relative;",
13482                     cn : [
13483                         {
13484                             cls : 'fc-view fc-view-month fc-grid',
13485                             style : 'position: relative',
13486                             unselectable : 'on',
13487                             cn : [
13488                                 {
13489                                     cls : 'fc-event-container',
13490                                     style : 'position:absolute;z-index:8;top:0;left:0;'
13491                                 },
13492                                 cal_table
13493                             ]
13494                         }
13495                     ]
13496     
13497                 }
13498            ] 
13499             
13500         };
13501         
13502          
13503         
13504         return cfg;
13505     },
13506     
13507     
13508     initEvents : function()
13509     {
13510         if(!this.store){
13511             throw "can not find store for calendar";
13512         }
13513         
13514         var mark = {
13515             tag: "div",
13516             cls:"x-dlg-mask",
13517             style: "text-align:center",
13518             cn: [
13519                 {
13520                     tag: "div",
13521                     style: "background-color:white;width:50%;margin:250 auto",
13522                     cn: [
13523                         {
13524                             tag: "img",
13525                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
13526                         },
13527                         {
13528                             tag: "span",
13529                             html: "Loading"
13530                         }
13531                         
13532                     ]
13533                 }
13534             ]
13535         }
13536         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13537         
13538         var size = this.el.select('.fc-content', true).first().getSize();
13539         this.maskEl.setSize(size.width, size.height);
13540         this.maskEl.enableDisplayMode("block");
13541         if(!this.loadMask){
13542             this.maskEl.hide();
13543         }
13544         
13545         this.store = Roo.factory(this.store, Roo.data);
13546         this.store.on('load', this.onLoad, this);
13547         this.store.on('beforeload', this.onBeforeLoad, this);
13548         
13549         this.resize();
13550         
13551         this.cells = this.el.select('.fc-day',true);
13552         //Roo.log(this.cells);
13553         this.textNodes = this.el.query('.fc-day-number');
13554         this.cells.addClassOnOver('fc-state-hover');
13555         
13556         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13557         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13558         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13559         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13560         
13561         this.on('monthchange', this.onMonthChange, this);
13562         
13563         this.update(new Date().clearTime());
13564     },
13565     
13566     resize : function() {
13567         var sz  = this.el.getSize();
13568         
13569         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13570         this.el.select('.fc-day-content div',true).setHeight(34);
13571     },
13572     
13573     
13574     // private
13575     showPrevMonth : function(e){
13576         this.update(this.activeDate.add("mo", -1));
13577     },
13578     showToday : function(e){
13579         this.update(new Date().clearTime());
13580     },
13581     // private
13582     showNextMonth : function(e){
13583         this.update(this.activeDate.add("mo", 1));
13584     },
13585
13586     // private
13587     showPrevYear : function(){
13588         this.update(this.activeDate.add("y", -1));
13589     },
13590
13591     // private
13592     showNextYear : function(){
13593         this.update(this.activeDate.add("y", 1));
13594     },
13595
13596     
13597    // private
13598     update : function(date)
13599     {
13600         var vd = this.activeDate;
13601         this.activeDate = date;
13602 //        if(vd && this.el){
13603 //            var t = date.getTime();
13604 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13605 //                Roo.log('using add remove');
13606 //                
13607 //                this.fireEvent('monthchange', this, date);
13608 //                
13609 //                this.cells.removeClass("fc-state-highlight");
13610 //                this.cells.each(function(c){
13611 //                   if(c.dateValue == t){
13612 //                       c.addClass("fc-state-highlight");
13613 //                       setTimeout(function(){
13614 //                            try{c.dom.firstChild.focus();}catch(e){}
13615 //                       }, 50);
13616 //                       return false;
13617 //                   }
13618 //                   return true;
13619 //                });
13620 //                return;
13621 //            }
13622 //        }
13623         
13624         var days = date.getDaysInMonth();
13625         
13626         var firstOfMonth = date.getFirstDateOfMonth();
13627         var startingPos = firstOfMonth.getDay()-this.startDay;
13628         
13629         if(startingPos < this.startDay){
13630             startingPos += 7;
13631         }
13632         
13633         var pm = date.add(Date.MONTH, -1);
13634         var prevStart = pm.getDaysInMonth()-startingPos;
13635 //        
13636         this.cells = this.el.select('.fc-day',true);
13637         this.textNodes = this.el.query('.fc-day-number');
13638         this.cells.addClassOnOver('fc-state-hover');
13639         
13640         var cells = this.cells.elements;
13641         var textEls = this.textNodes;
13642         
13643         Roo.each(cells, function(cell){
13644             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13645         });
13646         
13647         days += startingPos;
13648
13649         // convert everything to numbers so it's fast
13650         var day = 86400000;
13651         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13652         //Roo.log(d);
13653         //Roo.log(pm);
13654         //Roo.log(prevStart);
13655         
13656         var today = new Date().clearTime().getTime();
13657         var sel = date.clearTime().getTime();
13658         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13659         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13660         var ddMatch = this.disabledDatesRE;
13661         var ddText = this.disabledDatesText;
13662         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13663         var ddaysText = this.disabledDaysText;
13664         var format = this.format;
13665         
13666         var setCellClass = function(cal, cell){
13667             cell.row = 0;
13668             cell.events = [];
13669             cell.more = [];
13670             //Roo.log('set Cell Class');
13671             cell.title = "";
13672             var t = d.getTime();
13673             
13674             //Roo.log(d);
13675             
13676             cell.dateValue = t;
13677             if(t == today){
13678                 cell.className += " fc-today";
13679                 cell.className += " fc-state-highlight";
13680                 cell.title = cal.todayText;
13681             }
13682             if(t == sel){
13683                 // disable highlight in other month..
13684                 //cell.className += " fc-state-highlight";
13685                 
13686             }
13687             // disabling
13688             if(t < min) {
13689                 cell.className = " fc-state-disabled";
13690                 cell.title = cal.minText;
13691                 return;
13692             }
13693             if(t > max) {
13694                 cell.className = " fc-state-disabled";
13695                 cell.title = cal.maxText;
13696                 return;
13697             }
13698             if(ddays){
13699                 if(ddays.indexOf(d.getDay()) != -1){
13700                     cell.title = ddaysText;
13701                     cell.className = " fc-state-disabled";
13702                 }
13703             }
13704             if(ddMatch && format){
13705                 var fvalue = d.dateFormat(format);
13706                 if(ddMatch.test(fvalue)){
13707                     cell.title = ddText.replace("%0", fvalue);
13708                     cell.className = " fc-state-disabled";
13709                 }
13710             }
13711             
13712             if (!cell.initialClassName) {
13713                 cell.initialClassName = cell.dom.className;
13714             }
13715             
13716             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
13717         };
13718
13719         var i = 0;
13720         
13721         for(; i < startingPos; i++) {
13722             textEls[i].innerHTML = (++prevStart);
13723             d.setDate(d.getDate()+1);
13724             
13725             cells[i].className = "fc-past fc-other-month";
13726             setCellClass(this, cells[i]);
13727         }
13728         
13729         var intDay = 0;
13730         
13731         for(; i < days; i++){
13732             intDay = i - startingPos + 1;
13733             textEls[i].innerHTML = (intDay);
13734             d.setDate(d.getDate()+1);
13735             
13736             cells[i].className = ''; // "x-date-active";
13737             setCellClass(this, cells[i]);
13738         }
13739         var extraDays = 0;
13740         
13741         for(; i < 42; i++) {
13742             textEls[i].innerHTML = (++extraDays);
13743             d.setDate(d.getDate()+1);
13744             
13745             cells[i].className = "fc-future fc-other-month";
13746             setCellClass(this, cells[i]);
13747         }
13748         
13749         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13750         
13751         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13752         
13753         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13754         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13755         
13756         if(totalRows != 6){
13757             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13758             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13759         }
13760         
13761         this.fireEvent('monthchange', this, date);
13762         
13763         
13764         /*
13765         if(!this.internalRender){
13766             var main = this.el.dom.firstChild;
13767             var w = main.offsetWidth;
13768             this.el.setWidth(w + this.el.getBorderWidth("lr"));
13769             Roo.fly(main).setWidth(w);
13770             this.internalRender = true;
13771             // opera does not respect the auto grow header center column
13772             // then, after it gets a width opera refuses to recalculate
13773             // without a second pass
13774             if(Roo.isOpera && !this.secondPass){
13775                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13776                 this.secondPass = true;
13777                 this.update.defer(10, this, [date]);
13778             }
13779         }
13780         */
13781         
13782     },
13783     
13784     findCell : function(dt) {
13785         dt = dt.clearTime().getTime();
13786         var ret = false;
13787         this.cells.each(function(c){
13788             //Roo.log("check " +c.dateValue + '?=' + dt);
13789             if(c.dateValue == dt){
13790                 ret = c;
13791                 return false;
13792             }
13793             return true;
13794         });
13795         
13796         return ret;
13797     },
13798     
13799     findCells : function(ev) {
13800         var s = ev.start.clone().clearTime().getTime();
13801        // Roo.log(s);
13802         var e= ev.end.clone().clearTime().getTime();
13803        // Roo.log(e);
13804         var ret = [];
13805         this.cells.each(function(c){
13806              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13807             
13808             if(c.dateValue > e){
13809                 return ;
13810             }
13811             if(c.dateValue < s){
13812                 return ;
13813             }
13814             ret.push(c);
13815         });
13816         
13817         return ret;    
13818     },
13819     
13820 //    findBestRow: function(cells)
13821 //    {
13822 //        var ret = 0;
13823 //        
13824 //        for (var i =0 ; i < cells.length;i++) {
13825 //            ret  = Math.max(cells[i].rows || 0,ret);
13826 //        }
13827 //        return ret;
13828 //        
13829 //    },
13830     
13831     
13832     addItem : function(ev)
13833     {
13834         // look for vertical location slot in
13835         var cells = this.findCells(ev);
13836         
13837 //        ev.row = this.findBestRow(cells);
13838         
13839         // work out the location.
13840         
13841         var crow = false;
13842         var rows = [];
13843         for(var i =0; i < cells.length; i++) {
13844             
13845             cells[i].row = cells[0].row;
13846             
13847             if(i == 0){
13848                 cells[i].row = cells[i].row + 1;
13849             }
13850             
13851             if (!crow) {
13852                 crow = {
13853                     start : cells[i],
13854                     end :  cells[i]
13855                 };
13856                 continue;
13857             }
13858             if (crow.start.getY() == cells[i].getY()) {
13859                 // on same row.
13860                 crow.end = cells[i];
13861                 continue;
13862             }
13863             // different row.
13864             rows.push(crow);
13865             crow = {
13866                 start: cells[i],
13867                 end : cells[i]
13868             };
13869             
13870         }
13871         
13872         rows.push(crow);
13873         ev.els = [];
13874         ev.rows = rows;
13875         ev.cells = cells;
13876         
13877         cells[0].events.push(ev);
13878         
13879         this.calevents.push(ev);
13880     },
13881     
13882     clearEvents: function() {
13883         
13884         if(!this.calevents){
13885             return;
13886         }
13887         
13888         Roo.each(this.cells.elements, function(c){
13889             c.row = 0;
13890             c.events = [];
13891             c.more = [];
13892         });
13893         
13894         Roo.each(this.calevents, function(e) {
13895             Roo.each(e.els, function(el) {
13896                 el.un('mouseenter' ,this.onEventEnter, this);
13897                 el.un('mouseleave' ,this.onEventLeave, this);
13898                 el.remove();
13899             },this);
13900         },this);
13901         
13902         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13903             e.remove();
13904         });
13905         
13906     },
13907     
13908     renderEvents: function()
13909     {   
13910         var _this = this;
13911         
13912         this.cells.each(function(c) {
13913             
13914             if(c.row < 5){
13915                 return;
13916             }
13917             
13918             var ev = c.events;
13919             
13920             var r = 4;
13921             if(c.row != c.events.length){
13922                 r = 4 - (4 - (c.row - c.events.length));
13923             }
13924             
13925             c.events = ev.slice(0, r);
13926             c.more = ev.slice(r);
13927             
13928             if(c.more.length && c.more.length == 1){
13929                 c.events.push(c.more.pop());
13930             }
13931             
13932             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13933             
13934         });
13935             
13936         this.cells.each(function(c) {
13937             
13938             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13939             
13940             
13941             for (var e = 0; e < c.events.length; e++){
13942                 var ev = c.events[e];
13943                 var rows = ev.rows;
13944                 
13945                 for(var i = 0; i < rows.length; i++) {
13946                 
13947                     // how many rows should it span..
13948
13949                     var  cfg = {
13950                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13951                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13952
13953                         unselectable : "on",
13954                         cn : [
13955                             {
13956                                 cls: 'fc-event-inner',
13957                                 cn : [
13958     //                                {
13959     //                                  tag:'span',
13960     //                                  cls: 'fc-event-time',
13961     //                                  html : cells.length > 1 ? '' : ev.time
13962     //                                },
13963                                     {
13964                                       tag:'span',
13965                                       cls: 'fc-event-title',
13966                                       html : String.format('{0}', ev.title)
13967                                     }
13968
13969
13970                                 ]
13971                             },
13972                             {
13973                                 cls: 'ui-resizable-handle ui-resizable-e',
13974                                 html : '&nbsp;&nbsp;&nbsp'
13975                             }
13976
13977                         ]
13978                     };
13979
13980                     if (i == 0) {
13981                         cfg.cls += ' fc-event-start';
13982                     }
13983                     if ((i+1) == rows.length) {
13984                         cfg.cls += ' fc-event-end';
13985                     }
13986
13987                     var ctr = _this.el.select('.fc-event-container',true).first();
13988                     var cg = ctr.createChild(cfg);
13989
13990                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13991                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13992
13993                     var r = (c.more.length) ? 1 : 0;
13994                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
13995                     cg.setWidth(ebox.right - sbox.x -2);
13996
13997                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
13998                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
13999                     cg.on('click', _this.onEventClick, _this, ev);
14000
14001                     ev.els.push(cg);
14002                     
14003                 }
14004                 
14005             }
14006             
14007             
14008             if(c.more.length){
14009                 var  cfg = {
14010                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14011                     style : 'position: absolute',
14012                     unselectable : "on",
14013                     cn : [
14014                         {
14015                             cls: 'fc-event-inner',
14016                             cn : [
14017                                 {
14018                                   tag:'span',
14019                                   cls: 'fc-event-title',
14020                                   html : 'More'
14021                                 }
14022
14023
14024                             ]
14025                         },
14026                         {
14027                             cls: 'ui-resizable-handle ui-resizable-e',
14028                             html : '&nbsp;&nbsp;&nbsp'
14029                         }
14030
14031                     ]
14032                 };
14033
14034                 var ctr = _this.el.select('.fc-event-container',true).first();
14035                 var cg = ctr.createChild(cfg);
14036
14037                 var sbox = c.select('.fc-day-content',true).first().getBox();
14038                 var ebox = c.select('.fc-day-content',true).first().getBox();
14039                 //Roo.log(cg);
14040                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
14041                 cg.setWidth(ebox.right - sbox.x -2);
14042
14043                 cg.on('click', _this.onMoreEventClick, _this, c.more);
14044                 
14045             }
14046             
14047         });
14048         
14049         
14050         
14051     },
14052     
14053     onEventEnter: function (e, el,event,d) {
14054         this.fireEvent('evententer', this, el, event);
14055     },
14056     
14057     onEventLeave: function (e, el,event,d) {
14058         this.fireEvent('eventleave', this, el, event);
14059     },
14060     
14061     onEventClick: function (e, el,event,d) {
14062         this.fireEvent('eventclick', this, el, event);
14063     },
14064     
14065     onMonthChange: function () {
14066         this.store.load();
14067     },
14068     
14069     onMoreEventClick: function(e, el, more)
14070     {
14071         var _this = this;
14072         
14073         this.calpopover.placement = 'right';
14074         this.calpopover.setTitle('More');
14075         
14076         this.calpopover.setContent('');
14077         
14078         var ctr = this.calpopover.el.select('.popover-content', true).first();
14079         
14080         Roo.each(more, function(m){
14081             var cfg = {
14082                 cls : 'fc-event-hori fc-event-draggable',
14083                 html : m.title
14084             }
14085             var cg = ctr.createChild(cfg);
14086             
14087             cg.on('click', _this.onEventClick, _this, m);
14088         });
14089         
14090         this.calpopover.show(el);
14091         
14092         
14093     },
14094     
14095     onLoad: function () 
14096     {   
14097         this.calevents = [];
14098         var cal = this;
14099         
14100         if(this.store.getCount() > 0){
14101             this.store.data.each(function(d){
14102                cal.addItem({
14103                     id : d.data.id,
14104                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14105                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14106                     time : d.data.start_time,
14107                     title : d.data.title,
14108                     description : d.data.description,
14109                     venue : d.data.venue
14110                 });
14111             });
14112         }
14113         
14114         this.renderEvents();
14115         
14116         if(this.calevents.length && this.loadMask){
14117             this.maskEl.hide();
14118         }
14119     },
14120     
14121     onBeforeLoad: function()
14122     {
14123         this.clearEvents();
14124         if(this.loadMask){
14125             this.maskEl.show();
14126         }
14127     }
14128 });
14129
14130  
14131  /*
14132  * - LGPL
14133  *
14134  * element
14135  * 
14136  */
14137
14138 /**
14139  * @class Roo.bootstrap.Popover
14140  * @extends Roo.bootstrap.Component
14141  * Bootstrap Popover class
14142  * @cfg {String} html contents of the popover   (or false to use children..)
14143  * @cfg {String} title of popover (or false to hide)
14144  * @cfg {String} placement how it is placed
14145  * @cfg {String} trigger click || hover (or false to trigger manually)
14146  * @cfg {String} over what (parent or false to trigger manually.)
14147  * @cfg {Number} delay - delay before showing
14148  
14149  * @constructor
14150  * Create a new Popover
14151  * @param {Object} config The config object
14152  */
14153
14154 Roo.bootstrap.Popover = function(config){
14155     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14156 };
14157
14158 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
14159     
14160     title: 'Fill in a title',
14161     html: false,
14162     
14163     placement : 'right',
14164     trigger : 'hover', // hover
14165     
14166     delay : 0,
14167     
14168     over: 'parent',
14169     
14170     can_build_overlaid : false,
14171     
14172     getChildContainer : function()
14173     {
14174         return this.el.select('.popover-content',true).first();
14175     },
14176     
14177     getAutoCreate : function(){
14178          Roo.log('make popover?');
14179         var cfg = {
14180            cls : 'popover roo-dynamic',
14181            style: 'display:block',
14182            cn : [
14183                 {
14184                     cls : 'arrow'
14185                 },
14186                 {
14187                     cls : 'popover-inner',
14188                     cn : [
14189                         {
14190                             tag: 'h3',
14191                             cls: 'popover-title',
14192                             html : this.title
14193                         },
14194                         {
14195                             cls : 'popover-content',
14196                             html : this.html
14197                         }
14198                     ]
14199                     
14200                 }
14201            ]
14202         };
14203         
14204         return cfg;
14205     },
14206     setTitle: function(str)
14207     {
14208         this.el.select('.popover-title',true).first().dom.innerHTML = str;
14209     },
14210     setContent: function(str)
14211     {
14212         this.el.select('.popover-content',true).first().dom.innerHTML = str;
14213     },
14214     // as it get's added to the bottom of the page.
14215     onRender : function(ct, position)
14216     {
14217         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14218         if(!this.el){
14219             var cfg = Roo.apply({},  this.getAutoCreate());
14220             cfg.id = Roo.id();
14221             
14222             if (this.cls) {
14223                 cfg.cls += ' ' + this.cls;
14224             }
14225             if (this.style) {
14226                 cfg.style = this.style;
14227             }
14228             Roo.log("adding to ")
14229             this.el = Roo.get(document.body).createChild(cfg, position);
14230             Roo.log(this.el);
14231         }
14232         this.initEvents();
14233     },
14234     
14235     initEvents : function()
14236     {
14237         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14238         this.el.enableDisplayMode('block');
14239         this.el.hide();
14240         if (this.over === false) {
14241             return; 
14242         }
14243         if (this.triggers === false) {
14244             return;
14245         }
14246         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14247         var triggers = this.trigger ? this.trigger.split(' ') : [];
14248         Roo.each(triggers, function(trigger) {
14249         
14250             if (trigger == 'click') {
14251                 on_el.on('click', this.toggle, this);
14252             } else if (trigger != 'manual') {
14253                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
14254                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14255       
14256                 on_el.on(eventIn  ,this.enter, this);
14257                 on_el.on(eventOut, this.leave, this);
14258             }
14259         }, this);
14260         
14261     },
14262     
14263     
14264     // private
14265     timeout : null,
14266     hoverState : null,
14267     
14268     toggle : function () {
14269         this.hoverState == 'in' ? this.leave() : this.enter();
14270     },
14271     
14272     enter : function () {
14273        
14274     
14275         clearTimeout(this.timeout);
14276     
14277         this.hoverState = 'in';
14278     
14279         if (!this.delay || !this.delay.show) {
14280             this.show();
14281             return;
14282         }
14283         var _t = this;
14284         this.timeout = setTimeout(function () {
14285             if (_t.hoverState == 'in') {
14286                 _t.show();
14287             }
14288         }, this.delay.show)
14289     },
14290     leave : function() {
14291         clearTimeout(this.timeout);
14292     
14293         this.hoverState = 'out';
14294     
14295         if (!this.delay || !this.delay.hide) {
14296             this.hide();
14297             return;
14298         }
14299         var _t = this;
14300         this.timeout = setTimeout(function () {
14301             if (_t.hoverState == 'out') {
14302                 _t.hide();
14303             }
14304         }, this.delay.hide)
14305     },
14306     
14307     show : function (on_el)
14308     {
14309         if (!on_el) {
14310             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14311         }
14312         // set content.
14313         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14314         if (this.html !== false) {
14315             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14316         }
14317         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14318         if (!this.title.length) {
14319             this.el.select('.popover-title',true).hide();
14320         }
14321         
14322         var placement = typeof this.placement == 'function' ?
14323             this.placement.call(this, this.el, on_el) :
14324             this.placement;
14325             
14326         var autoToken = /\s?auto?\s?/i;
14327         var autoPlace = autoToken.test(placement);
14328         if (autoPlace) {
14329             placement = placement.replace(autoToken, '') || 'top';
14330         }
14331         
14332         //this.el.detach()
14333         //this.el.setXY([0,0]);
14334         this.el.show();
14335         this.el.dom.style.display='block';
14336         this.el.addClass(placement);
14337         
14338         //this.el.appendTo(on_el);
14339         
14340         var p = this.getPosition();
14341         var box = this.el.getBox();
14342         
14343         if (autoPlace) {
14344             // fixme..
14345         }
14346         var align = Roo.bootstrap.Popover.alignment[placement];
14347         this.el.alignTo(on_el, align[0],align[1]);
14348         //var arrow = this.el.select('.arrow',true).first();
14349         //arrow.set(align[2], 
14350         
14351         this.el.addClass('in');
14352         this.hoverState = null;
14353         
14354         if (this.el.hasClass('fade')) {
14355             // fade it?
14356         }
14357         
14358     },
14359     hide : function()
14360     {
14361         this.el.setXY([0,0]);
14362         this.el.removeClass('in');
14363         this.el.hide();
14364         
14365     }
14366     
14367 });
14368
14369 Roo.bootstrap.Popover.alignment = {
14370     'left' : ['r-l', [-10,0], 'right'],
14371     'right' : ['l-r', [10,0], 'left'],
14372     'bottom' : ['t-b', [0,10], 'top'],
14373     'top' : [ 'b-t', [0,-10], 'bottom']
14374 };
14375
14376  /*
14377  * - LGPL
14378  *
14379  * Progress
14380  * 
14381  */
14382
14383 /**
14384  * @class Roo.bootstrap.Progress
14385  * @extends Roo.bootstrap.Component
14386  * Bootstrap Progress class
14387  * @cfg {Boolean} striped striped of the progress bar
14388  * @cfg {Boolean} active animated of the progress bar
14389  * 
14390  * 
14391  * @constructor
14392  * Create a new Progress
14393  * @param {Object} config The config object
14394  */
14395
14396 Roo.bootstrap.Progress = function(config){
14397     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14398 };
14399
14400 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
14401     
14402     striped : false,
14403     active: false,
14404     
14405     getAutoCreate : function(){
14406         var cfg = {
14407             tag: 'div',
14408             cls: 'progress'
14409         };
14410         
14411         
14412         if(this.striped){
14413             cfg.cls += ' progress-striped';
14414         }
14415       
14416         if(this.active){
14417             cfg.cls += ' active';
14418         }
14419         
14420         
14421         return cfg;
14422     }
14423    
14424 });
14425
14426  
14427
14428  /*
14429  * - LGPL
14430  *
14431  * ProgressBar
14432  * 
14433  */
14434
14435 /**
14436  * @class Roo.bootstrap.ProgressBar
14437  * @extends Roo.bootstrap.Component
14438  * Bootstrap ProgressBar class
14439  * @cfg {Number} aria_valuenow aria-value now
14440  * @cfg {Number} aria_valuemin aria-value min
14441  * @cfg {Number} aria_valuemax aria-value max
14442  * @cfg {String} label label for the progress bar
14443  * @cfg {String} panel (success | info | warning | danger )
14444  * @cfg {String} role role of the progress bar
14445  * @cfg {String} sr_only text
14446  * 
14447  * 
14448  * @constructor
14449  * Create a new ProgressBar
14450  * @param {Object} config The config object
14451  */
14452
14453 Roo.bootstrap.ProgressBar = function(config){
14454     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14455 };
14456
14457 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
14458     
14459     aria_valuenow : 0,
14460     aria_valuemin : 0,
14461     aria_valuemax : 100,
14462     label : false,
14463     panel : false,
14464     role : false,
14465     sr_only: false,
14466     
14467     getAutoCreate : function()
14468     {
14469         
14470         var cfg = {
14471             tag: 'div',
14472             cls: 'progress-bar',
14473             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14474         };
14475         
14476         if(this.sr_only){
14477             cfg.cn = {
14478                 tag: 'span',
14479                 cls: 'sr-only',
14480                 html: this.sr_only
14481             }
14482         }
14483         
14484         if(this.role){
14485             cfg.role = this.role;
14486         }
14487         
14488         if(this.aria_valuenow){
14489             cfg['aria-valuenow'] = this.aria_valuenow;
14490         }
14491         
14492         if(this.aria_valuemin){
14493             cfg['aria-valuemin'] = this.aria_valuemin;
14494         }
14495         
14496         if(this.aria_valuemax){
14497             cfg['aria-valuemax'] = this.aria_valuemax;
14498         }
14499         
14500         if(this.label && !this.sr_only){
14501             cfg.html = this.label;
14502         }
14503         
14504         if(this.panel){
14505             cfg.cls += ' progress-bar-' + this.panel;
14506         }
14507         
14508         return cfg;
14509     },
14510     
14511     update : function(aria_valuenow)
14512     {
14513         this.aria_valuenow = aria_valuenow;
14514         
14515         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14516     }
14517    
14518 });
14519
14520  
14521
14522  /*
14523  * - LGPL
14524  *
14525  * column
14526  * 
14527  */
14528
14529 /**
14530  * @class Roo.bootstrap.TabGroup
14531  * @extends Roo.bootstrap.Column
14532  * Bootstrap Column class
14533  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14534  * @cfg {Boolean} carousel true to make the group behave like a carousel
14535  * 
14536  * @constructor
14537  * Create a new TabGroup
14538  * @param {Object} config The config object
14539  */
14540
14541 Roo.bootstrap.TabGroup = function(config){
14542     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14543     if (!this.navId) {
14544         this.navId = Roo.id();
14545     }
14546     this.tabs = [];
14547     Roo.bootstrap.TabGroup.register(this);
14548     
14549 };
14550
14551 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
14552     
14553     carousel : false,
14554     transition : false,
14555      
14556     getAutoCreate : function()
14557     {
14558         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14559         
14560         cfg.cls += ' tab-content';
14561         
14562         if (this.carousel) {
14563             cfg.cls += ' carousel slide';
14564             cfg.cn = [{
14565                cls : 'carousel-inner'
14566             }]
14567         }
14568         
14569         
14570         return cfg;
14571     },
14572     getChildContainer : function()
14573     {
14574         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14575     },
14576     
14577     /**
14578     * register a Navigation item
14579     * @param {Roo.bootstrap.NavItem} the navitem to add
14580     */
14581     register : function(item)
14582     {
14583         this.tabs.push( item);
14584         item.navId = this.navId; // not really needed..
14585     
14586     },
14587     
14588     getActivePanel : function()
14589     {
14590         var r = false;
14591         Roo.each(this.tabs, function(t) {
14592             if (t.active) {
14593                 r = t;
14594                 return false;
14595             }
14596             return null;
14597         });
14598         return r;
14599         
14600     },
14601     getPanelByName : function(n)
14602     {
14603         var r = false;
14604         Roo.each(this.tabs, function(t) {
14605             if (t.tabId == n) {
14606                 r = t;
14607                 return false;
14608             }
14609             return null;
14610         });
14611         return r;
14612     },
14613     indexOfPanel : function(p)
14614     {
14615         var r = false;
14616         Roo.each(this.tabs, function(t,i) {
14617             if (t.tabId == p.tabId) {
14618                 r = i;
14619                 return false;
14620             }
14621             return null;
14622         });
14623         return r;
14624     },
14625     /**
14626      * show a specific panel
14627      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14628      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14629      */
14630     showPanel : function (pan)
14631     {
14632         
14633         if (typeof(pan) == 'number') {
14634             pan = this.tabs[pan];
14635         }
14636         if (typeof(pan) == 'string') {
14637             pan = this.getPanelByName(pan);
14638         }
14639         if (pan.tabId == this.getActivePanel().tabId) {
14640             return true;
14641         }
14642         var cur = this.getActivePanel();
14643         
14644         if (false === cur.fireEvent('beforedeactivate')) {
14645             return false;
14646         }
14647         
14648         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14649             
14650             this.transition = true;
14651             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
14652             var lr = dir == 'next' ? 'left' : 'right';
14653             pan.el.addClass(dir); // or prev
14654             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14655             cur.el.addClass(lr); // or right
14656             pan.el.addClass(lr);
14657             
14658             var _this = this;
14659             cur.el.on('transitionend', function() {
14660                 Roo.log("trans end?");
14661                 
14662                 pan.el.removeClass([lr,dir]);
14663                 pan.setActive(true);
14664                 
14665                 cur.el.removeClass([lr]);
14666                 cur.setActive(false);
14667                 
14668                 _this.transition = false;
14669                 
14670             }, this, { single:  true } );
14671             return true;
14672         }
14673         
14674         cur.setActive(false);
14675         pan.setActive(true);
14676         return true;
14677         
14678     },
14679     showPanelNext : function()
14680     {
14681         var i = this.indexOfPanel(this.getActivePanel());
14682         if (i > this.tabs.length) {
14683             return;
14684         }
14685         this.showPanel(this.tabs[i+1]);
14686     },
14687     showPanelPrev : function()
14688     {
14689         var i = this.indexOfPanel(this.getActivePanel());
14690         if (i  < 1) {
14691             return;
14692         }
14693         this.showPanel(this.tabs[i-1]);
14694     }
14695     
14696     
14697   
14698 });
14699
14700  
14701
14702  
14703  
14704 Roo.apply(Roo.bootstrap.TabGroup, {
14705     
14706     groups: {},
14707      /**
14708     * register a Navigation Group
14709     * @param {Roo.bootstrap.NavGroup} the navgroup to add
14710     */
14711     register : function(navgrp)
14712     {
14713         this.groups[navgrp.navId] = navgrp;
14714         
14715     },
14716     /**
14717     * fetch a Navigation Group based on the navigation ID
14718     * if one does not exist , it will get created.
14719     * @param {string} the navgroup to add
14720     * @returns {Roo.bootstrap.NavGroup} the navgroup 
14721     */
14722     get: function(navId) {
14723         if (typeof(this.groups[navId]) == 'undefined') {
14724             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14725         }
14726         return this.groups[navId] ;
14727     }
14728     
14729     
14730     
14731 });
14732
14733  /*
14734  * - LGPL
14735  *
14736  * TabPanel
14737  * 
14738  */
14739
14740 /**
14741  * @class Roo.bootstrap.TabPanel
14742  * @extends Roo.bootstrap.Component
14743  * Bootstrap TabPanel class
14744  * @cfg {Boolean} active panel active
14745  * @cfg {String} html panel content
14746  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14747  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14748  * 
14749  * 
14750  * @constructor
14751  * Create a new TabPanel
14752  * @param {Object} config The config object
14753  */
14754
14755 Roo.bootstrap.TabPanel = function(config){
14756     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14757     this.addEvents({
14758         /**
14759              * @event changed
14760              * Fires when the active status changes
14761              * @param {Roo.bootstrap.TabPanel} this
14762              * @param {Boolean} state the new state
14763             
14764          */
14765         'changed': true,
14766         /**
14767              * @event beforedeactivate
14768              * Fires before a tab is de-activated - can be used to do validation on a form.
14769              * @param {Roo.bootstrap.TabPanel} this
14770              * @return {Boolean} false if there is an error
14771             
14772          */
14773         'beforedeactivate': true
14774      });
14775     
14776     this.tabId = this.tabId || Roo.id();
14777   
14778 };
14779
14780 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
14781     
14782     active: false,
14783     html: false,
14784     tabId: false,
14785     navId : false,
14786     
14787     getAutoCreate : function(){
14788         var cfg = {
14789             tag: 'div',
14790             // item is needed for carousel - not sure if it has any effect otherwise
14791             cls: 'tab-pane item',
14792             html: this.html || ''
14793         };
14794         
14795         if(this.active){
14796             cfg.cls += ' active';
14797         }
14798         
14799         if(this.tabId){
14800             cfg.tabId = this.tabId;
14801         }
14802         
14803         
14804         return cfg;
14805     },
14806     
14807     initEvents:  function()
14808     {
14809         Roo.log('-------- init events on tab panel ---------');
14810         
14811         var p = this.parent();
14812         this.navId = this.navId || p.navId;
14813         
14814         if (typeof(this.navId) != 'undefined') {
14815             // not really needed.. but just in case.. parent should be a NavGroup.
14816             var tg = Roo.bootstrap.TabGroup.get(this.navId);
14817             Roo.log(['register', tg, this]);
14818             tg.register(this);
14819         }
14820     },
14821     
14822     
14823     onRender : function(ct, position)
14824     {
14825        // Roo.log("Call onRender: " + this.xtype);
14826         
14827         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14828         
14829         
14830         
14831         
14832         
14833     },
14834     
14835     setActive: function(state)
14836     {
14837         Roo.log("panel - set active " + this.tabId + "=" + state);
14838         
14839         this.active = state;
14840         if (!state) {
14841             this.el.removeClass('active');
14842             
14843         } else  if (!this.el.hasClass('active')) {
14844             this.el.addClass('active');
14845         }
14846         this.fireEvent('changed', this, state);
14847     }
14848     
14849     
14850 });
14851  
14852
14853  
14854
14855  /*
14856  * - LGPL
14857  *
14858  * DateField
14859  * 
14860  */
14861
14862 /**
14863  * @class Roo.bootstrap.DateField
14864  * @extends Roo.bootstrap.Input
14865  * Bootstrap DateField class
14866  * @cfg {Number} weekStart default 0
14867  * @cfg {String} viewMode default empty, (months|years)
14868  * @cfg {String} minViewMode default empty, (months|years)
14869  * @cfg {Number} startDate default -Infinity
14870  * @cfg {Number} endDate default Infinity
14871  * @cfg {Boolean} todayHighlight default false
14872  * @cfg {Boolean} todayBtn default false
14873  * @cfg {Boolean} calendarWeeks default false
14874  * @cfg {Object} daysOfWeekDisabled default empty
14875  * @cfg {Boolean} singleMode default false (true | false)
14876  * 
14877  * @cfg {Boolean} keyboardNavigation default true
14878  * @cfg {String} language default en
14879  * 
14880  * @constructor
14881  * Create a new DateField
14882  * @param {Object} config The config object
14883  */
14884
14885 Roo.bootstrap.DateField = function(config){
14886     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14887      this.addEvents({
14888             /**
14889              * @event show
14890              * Fires when this field show.
14891              * @param {Roo.bootstrap.DateField} this
14892              * @param {Mixed} date The date value
14893              */
14894             show : true,
14895             /**
14896              * @event show
14897              * Fires when this field hide.
14898              * @param {Roo.bootstrap.DateField} this
14899              * @param {Mixed} date The date value
14900              */
14901             hide : true,
14902             /**
14903              * @event select
14904              * Fires when select a date.
14905              * @param {Roo.bootstrap.DateField} this
14906              * @param {Mixed} date The date value
14907              */
14908             select : true
14909         });
14910 };
14911
14912 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
14913     
14914     /**
14915      * @cfg {String} format
14916      * The default date format string which can be overriden for localization support.  The format must be
14917      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14918      */
14919     format : "m/d/y",
14920     /**
14921      * @cfg {String} altFormats
14922      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14923      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14924      */
14925     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14926     
14927     weekStart : 0,
14928     
14929     viewMode : '',
14930     
14931     minViewMode : '',
14932     
14933     todayHighlight : false,
14934     
14935     todayBtn: false,
14936     
14937     language: 'en',
14938     
14939     keyboardNavigation: true,
14940     
14941     calendarWeeks: false,
14942     
14943     startDate: -Infinity,
14944     
14945     endDate: Infinity,
14946     
14947     daysOfWeekDisabled: [],
14948     
14949     _events: [],
14950     
14951     singleMode : false,
14952     
14953     UTCDate: function()
14954     {
14955         return new Date(Date.UTC.apply(Date, arguments));
14956     },
14957     
14958     UTCToday: function()
14959     {
14960         var today = new Date();
14961         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14962     },
14963     
14964     getDate: function() {
14965             var d = this.getUTCDate();
14966             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14967     },
14968     
14969     getUTCDate: function() {
14970             return this.date;
14971     },
14972     
14973     setDate: function(d) {
14974             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14975     },
14976     
14977     setUTCDate: function(d) {
14978             this.date = d;
14979             this.setValue(this.formatDate(this.date));
14980     },
14981         
14982     onRender: function(ct, position)
14983     {
14984         
14985         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14986         
14987         this.language = this.language || 'en';
14988         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14989         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14990         
14991         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14992         this.format = this.format || 'm/d/y';
14993         this.isInline = false;
14994         this.isInput = true;
14995         this.component = this.el.select('.add-on', true).first() || false;
14996         this.component = (this.component && this.component.length === 0) ? false : this.component;
14997         this.hasInput = this.component && this.inputEL().length;
14998         
14999         if (typeof(this.minViewMode === 'string')) {
15000             switch (this.minViewMode) {
15001                 case 'months':
15002                     this.minViewMode = 1;
15003                     break;
15004                 case 'years':
15005                     this.minViewMode = 2;
15006                     break;
15007                 default:
15008                     this.minViewMode = 0;
15009                     break;
15010             }
15011         }
15012         
15013         if (typeof(this.viewMode === 'string')) {
15014             switch (this.viewMode) {
15015                 case 'months':
15016                     this.viewMode = 1;
15017                     break;
15018                 case 'years':
15019                     this.viewMode = 2;
15020                     break;
15021                 default:
15022                     this.viewMode = 0;
15023                     break;
15024             }
15025         }
15026                 
15027         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15028         
15029 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15030         
15031         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15032         
15033         this.picker().on('mousedown', this.onMousedown, this);
15034         this.picker().on('click', this.onClick, this);
15035         
15036         this.picker().addClass('datepicker-dropdown');
15037         
15038         this.startViewMode = this.viewMode;
15039         
15040         if(this.singleMode){
15041             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15042                 v.setVisibilityMode(Roo.Element.DISPLAY)
15043                 v.hide();
15044             });
15045             
15046             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15047                 v.setStyle('width', '189px');
15048             });
15049         }
15050         
15051         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15052             if(!this.calendarWeeks){
15053                 v.remove();
15054                 return;
15055             }
15056             
15057             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15058             v.attr('colspan', function(i, val){
15059                 return parseInt(val) + 1;
15060             });
15061         })
15062                         
15063         
15064         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15065         
15066         this.setStartDate(this.startDate);
15067         this.setEndDate(this.endDate);
15068         
15069         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15070         
15071         this.fillDow();
15072         this.fillMonths();
15073         this.update();
15074         this.showMode();
15075         
15076         if(this.isInline) {
15077             this.show();
15078         }
15079     },
15080     
15081     picker : function()
15082     {
15083         return this.pickerEl;
15084 //        return this.el.select('.datepicker', true).first();
15085     },
15086     
15087     fillDow: function()
15088     {
15089         var dowCnt = this.weekStart;
15090         
15091         var dow = {
15092             tag: 'tr',
15093             cn: [
15094                 
15095             ]
15096         };
15097         
15098         if(this.calendarWeeks){
15099             dow.cn.push({
15100                 tag: 'th',
15101                 cls: 'cw',
15102                 html: '&nbsp;'
15103             })
15104         }
15105         
15106         while (dowCnt < this.weekStart + 7) {
15107             dow.cn.push({
15108                 tag: 'th',
15109                 cls: 'dow',
15110                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15111             });
15112         }
15113         
15114         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15115     },
15116     
15117     fillMonths: function()
15118     {    
15119         var i = 0;
15120         var months = this.picker().select('>.datepicker-months td', true).first();
15121         
15122         months.dom.innerHTML = '';
15123         
15124         while (i < 12) {
15125             var month = {
15126                 tag: 'span',
15127                 cls: 'month',
15128                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15129             }
15130             
15131             months.createChild(month);
15132         }
15133         
15134     },
15135     
15136     update: function()
15137     {
15138         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;
15139         
15140         if (this.date < this.startDate) {
15141             this.viewDate = new Date(this.startDate);
15142         } else if (this.date > this.endDate) {
15143             this.viewDate = new Date(this.endDate);
15144         } else {
15145             this.viewDate = new Date(this.date);
15146         }
15147         
15148         this.fill();
15149     },
15150     
15151     fill: function() 
15152     {
15153         var d = new Date(this.viewDate),
15154                 year = d.getUTCFullYear(),
15155                 month = d.getUTCMonth(),
15156                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15157                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15158                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15159                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15160                 currentDate = this.date && this.date.valueOf(),
15161                 today = this.UTCToday();
15162         
15163         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15164         
15165 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15166         
15167 //        this.picker.select('>tfoot th.today').
15168 //                                              .text(dates[this.language].today)
15169 //                                              .toggle(this.todayBtn !== false);
15170     
15171         this.updateNavArrows();
15172         this.fillMonths();
15173                                                 
15174         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15175         
15176         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15177          
15178         prevMonth.setUTCDate(day);
15179         
15180         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15181         
15182         var nextMonth = new Date(prevMonth);
15183         
15184         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15185         
15186         nextMonth = nextMonth.valueOf();
15187         
15188         var fillMonths = false;
15189         
15190         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15191         
15192         while(prevMonth.valueOf() < nextMonth) {
15193             var clsName = '';
15194             
15195             if (prevMonth.getUTCDay() === this.weekStart) {
15196                 if(fillMonths){
15197                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15198                 }
15199                     
15200                 fillMonths = {
15201                     tag: 'tr',
15202                     cn: []
15203                 };
15204                 
15205                 if(this.calendarWeeks){
15206                     // ISO 8601: First week contains first thursday.
15207                     // ISO also states week starts on Monday, but we can be more abstract here.
15208                     var
15209                     // Start of current week: based on weekstart/current date
15210                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15211                     // Thursday of this week
15212                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15213                     // First Thursday of year, year from thursday
15214                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15215                     // Calendar week: ms between thursdays, div ms per day, div 7 days
15216                     calWeek =  (th - yth) / 864e5 / 7 + 1;
15217                     
15218                     fillMonths.cn.push({
15219                         tag: 'td',
15220                         cls: 'cw',
15221                         html: calWeek
15222                     });
15223                 }
15224             }
15225             
15226             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15227                 clsName += ' old';
15228             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15229                 clsName += ' new';
15230             }
15231             if (this.todayHighlight &&
15232                 prevMonth.getUTCFullYear() == today.getFullYear() &&
15233                 prevMonth.getUTCMonth() == today.getMonth() &&
15234                 prevMonth.getUTCDate() == today.getDate()) {
15235                 clsName += ' today';
15236             }
15237             
15238             if (currentDate && prevMonth.valueOf() === currentDate) {
15239                 clsName += ' active';
15240             }
15241             
15242             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15243                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15244                     clsName += ' disabled';
15245             }
15246             
15247             fillMonths.cn.push({
15248                 tag: 'td',
15249                 cls: 'day ' + clsName,
15250                 html: prevMonth.getDate()
15251             })
15252             
15253             prevMonth.setDate(prevMonth.getDate()+1);
15254         }
15255           
15256         var currentYear = this.date && this.date.getUTCFullYear();
15257         var currentMonth = this.date && this.date.getUTCMonth();
15258         
15259         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15260         
15261         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15262             v.removeClass('active');
15263             
15264             if(currentYear === year && k === currentMonth){
15265                 v.addClass('active');
15266             }
15267             
15268             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15269                 v.addClass('disabled');
15270             }
15271             
15272         });
15273         
15274         
15275         year = parseInt(year/10, 10) * 10;
15276         
15277         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15278         
15279         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15280         
15281         year -= 1;
15282         for (var i = -1; i < 11; i++) {
15283             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15284                 tag: 'span',
15285                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15286                 html: year
15287             })
15288             
15289             year += 1;
15290         }
15291     },
15292     
15293     showMode: function(dir) 
15294     {
15295         if (dir) {
15296             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15297         }
15298         
15299         Roo.each(this.picker().select('>div',true).elements, function(v){
15300             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15301             v.hide();
15302         });
15303         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15304     },
15305     
15306     place: function()
15307     {
15308         if(this.isInline) return;
15309         
15310         this.picker().removeClass(['bottom', 'top']);
15311         
15312         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15313             /*
15314              * place to the top of element!
15315              *
15316              */
15317             
15318             this.picker().addClass('top');
15319             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15320             
15321             return;
15322         }
15323         
15324         this.picker().addClass('bottom');
15325         
15326         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15327     },
15328     
15329     parseDate : function(value)
15330     {
15331         if(!value || value instanceof Date){
15332             return value;
15333         }
15334         var v = Date.parseDate(value, this.format);
15335         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15336             v = Date.parseDate(value, 'Y-m-d');
15337         }
15338         if(!v && this.altFormats){
15339             if(!this.altFormatsArray){
15340                 this.altFormatsArray = this.altFormats.split("|");
15341             }
15342             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15343                 v = Date.parseDate(value, this.altFormatsArray[i]);
15344             }
15345         }
15346         return v;
15347     },
15348     
15349     formatDate : function(date, fmt)
15350     {   
15351         return (!date || !(date instanceof Date)) ?
15352         date : date.dateFormat(fmt || this.format);
15353     },
15354     
15355     onFocus : function()
15356     {
15357         Roo.bootstrap.DateField.superclass.onFocus.call(this);
15358         this.show();
15359     },
15360     
15361     onBlur : function()
15362     {
15363         Roo.bootstrap.DateField.superclass.onBlur.call(this);
15364         
15365         var d = this.inputEl().getValue();
15366         
15367         this.setValue(d);
15368                 
15369         this.hide();
15370     },
15371     
15372     show : function()
15373     {
15374         this.picker().show();
15375         this.update();
15376         this.place();
15377         
15378         this.fireEvent('show', this, this.date);
15379     },
15380     
15381     hide : function()
15382     {
15383         if(this.isInline) return;
15384         this.picker().hide();
15385         this.viewMode = this.startViewMode;
15386         this.showMode();
15387         
15388         this.fireEvent('hide', this, this.date);
15389         
15390     },
15391     
15392     onMousedown: function(e)
15393     {
15394         e.stopPropagation();
15395         e.preventDefault();
15396     },
15397     
15398     keyup: function(e)
15399     {
15400         Roo.bootstrap.DateField.superclass.keyup.call(this);
15401         this.update();
15402     },
15403
15404     setValue: function(v)
15405     {
15406         
15407         // v can be a string or a date..
15408         
15409         
15410         var d = new Date(this.parseDate(v) ).clearTime();
15411         
15412         if(isNaN(d.getTime())){
15413             this.date = this.viewDate = '';
15414             Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15415             return;
15416         }
15417         
15418         v = this.formatDate(d);
15419         
15420         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15421         
15422         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15423      
15424         this.update();
15425
15426         this.fireEvent('select', this, this.date);
15427         
15428     },
15429     
15430     getValue: function()
15431     {
15432         return this.formatDate(this.date);
15433     },
15434     
15435     fireKey: function(e)
15436     {
15437         if (!this.picker().isVisible()){
15438             if (e.keyCode == 27) // allow escape to hide and re-show picker
15439                 this.show();
15440             return;
15441         }
15442         
15443         var dateChanged = false,
15444         dir, day, month,
15445         newDate, newViewDate;
15446         
15447         switch(e.keyCode){
15448             case 27: // escape
15449                 this.hide();
15450                 e.preventDefault();
15451                 break;
15452             case 37: // left
15453             case 39: // right
15454                 if (!this.keyboardNavigation) break;
15455                 dir = e.keyCode == 37 ? -1 : 1;
15456                 
15457                 if (e.ctrlKey){
15458                     newDate = this.moveYear(this.date, dir);
15459                     newViewDate = this.moveYear(this.viewDate, dir);
15460                 } else if (e.shiftKey){
15461                     newDate = this.moveMonth(this.date, dir);
15462                     newViewDate = this.moveMonth(this.viewDate, dir);
15463                 } else {
15464                     newDate = new Date(this.date);
15465                     newDate.setUTCDate(this.date.getUTCDate() + dir);
15466                     newViewDate = new Date(this.viewDate);
15467                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15468                 }
15469                 if (this.dateWithinRange(newDate)){
15470                     this.date = newDate;
15471                     this.viewDate = newViewDate;
15472                     this.setValue(this.formatDate(this.date));
15473 //                    this.update();
15474                     e.preventDefault();
15475                     dateChanged = true;
15476                 }
15477                 break;
15478             case 38: // up
15479             case 40: // down
15480                 if (!this.keyboardNavigation) break;
15481                 dir = e.keyCode == 38 ? -1 : 1;
15482                 if (e.ctrlKey){
15483                     newDate = this.moveYear(this.date, dir);
15484                     newViewDate = this.moveYear(this.viewDate, dir);
15485                 } else if (e.shiftKey){
15486                     newDate = this.moveMonth(this.date, dir);
15487                     newViewDate = this.moveMonth(this.viewDate, dir);
15488                 } else {
15489                     newDate = new Date(this.date);
15490                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15491                     newViewDate = new Date(this.viewDate);
15492                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15493                 }
15494                 if (this.dateWithinRange(newDate)){
15495                     this.date = newDate;
15496                     this.viewDate = newViewDate;
15497                     this.setValue(this.formatDate(this.date));
15498 //                    this.update();
15499                     e.preventDefault();
15500                     dateChanged = true;
15501                 }
15502                 break;
15503             case 13: // enter
15504                 this.setValue(this.formatDate(this.date));
15505                 this.hide();
15506                 e.preventDefault();
15507                 break;
15508             case 9: // tab
15509                 this.setValue(this.formatDate(this.date));
15510                 this.hide();
15511                 break;
15512             case 16: // shift
15513             case 17: // ctrl
15514             case 18: // alt
15515                 break;
15516             default :
15517                 this.hide();
15518                 
15519         }
15520     },
15521     
15522     
15523     onClick: function(e) 
15524     {
15525         e.stopPropagation();
15526         e.preventDefault();
15527         
15528         var target = e.getTarget();
15529         
15530         if(target.nodeName.toLowerCase() === 'i'){
15531             target = Roo.get(target).dom.parentNode;
15532         }
15533         
15534         var nodeName = target.nodeName;
15535         var className = target.className;
15536         var html = target.innerHTML;
15537         //Roo.log(nodeName);
15538         
15539         switch(nodeName.toLowerCase()) {
15540             case 'th':
15541                 switch(className) {
15542                     case 'switch':
15543                         this.showMode(1);
15544                         break;
15545                     case 'prev':
15546                     case 'next':
15547                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15548                         switch(this.viewMode){
15549                                 case 0:
15550                                         this.viewDate = this.moveMonth(this.viewDate, dir);
15551                                         break;
15552                                 case 1:
15553                                 case 2:
15554                                         this.viewDate = this.moveYear(this.viewDate, dir);
15555                                         break;
15556                         }
15557                         this.fill();
15558                         break;
15559                     case 'today':
15560                         var date = new Date();
15561                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15562 //                        this.fill()
15563                         this.setValue(this.formatDate(this.date));
15564                         
15565                         this.hide();
15566                         break;
15567                 }
15568                 break;
15569             case 'span':
15570                 if (className.indexOf('disabled') < 0) {
15571                     this.viewDate.setUTCDate(1);
15572                     if (className.indexOf('month') > -1) {
15573                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15574                     } else {
15575                         var year = parseInt(html, 10) || 0;
15576                         this.viewDate.setUTCFullYear(year);
15577                         
15578                     }
15579                     
15580                     if(this.singleMode){
15581                         this.setValue(this.formatDate(this.viewDate));
15582                         this.hide();
15583                         return;
15584                     }
15585                     
15586                     this.showMode(-1);
15587                     this.fill();
15588                 }
15589                 break;
15590                 
15591             case 'td':
15592                 //Roo.log(className);
15593                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15594                     var day = parseInt(html, 10) || 1;
15595                     var year = this.viewDate.getUTCFullYear(),
15596                         month = this.viewDate.getUTCMonth();
15597
15598                     if (className.indexOf('old') > -1) {
15599                         if(month === 0 ){
15600                             month = 11;
15601                             year -= 1;
15602                         }else{
15603                             month -= 1;
15604                         }
15605                     } else if (className.indexOf('new') > -1) {
15606                         if (month == 11) {
15607                             month = 0;
15608                             year += 1;
15609                         } else {
15610                             month += 1;
15611                         }
15612                     }
15613                     //Roo.log([year,month,day]);
15614                     this.date = this.UTCDate(year, month, day,0,0,0,0);
15615                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15616 //                    this.fill();
15617                     //Roo.log(this.formatDate(this.date));
15618                     this.setValue(this.formatDate(this.date));
15619                     this.hide();
15620                 }
15621                 break;
15622         }
15623     },
15624     
15625     setStartDate: function(startDate)
15626     {
15627         this.startDate = startDate || -Infinity;
15628         if (this.startDate !== -Infinity) {
15629             this.startDate = this.parseDate(this.startDate);
15630         }
15631         this.update();
15632         this.updateNavArrows();
15633     },
15634
15635     setEndDate: function(endDate)
15636     {
15637         this.endDate = endDate || Infinity;
15638         if (this.endDate !== Infinity) {
15639             this.endDate = this.parseDate(this.endDate);
15640         }
15641         this.update();
15642         this.updateNavArrows();
15643     },
15644     
15645     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15646     {
15647         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15648         if (typeof(this.daysOfWeekDisabled) !== 'object') {
15649             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15650         }
15651         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15652             return parseInt(d, 10);
15653         });
15654         this.update();
15655         this.updateNavArrows();
15656     },
15657     
15658     updateNavArrows: function() 
15659     {
15660         if(this.singleMode){
15661             return;
15662         }
15663         
15664         var d = new Date(this.viewDate),
15665         year = d.getUTCFullYear(),
15666         month = d.getUTCMonth();
15667         
15668         Roo.each(this.picker().select('.prev', true).elements, function(v){
15669             v.show();
15670             switch (this.viewMode) {
15671                 case 0:
15672
15673                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15674                         v.hide();
15675                     }
15676                     break;
15677                 case 1:
15678                 case 2:
15679                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15680                         v.hide();
15681                     }
15682                     break;
15683             }
15684         });
15685         
15686         Roo.each(this.picker().select('.next', true).elements, function(v){
15687             v.show();
15688             switch (this.viewMode) {
15689                 case 0:
15690
15691                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15692                         v.hide();
15693                     }
15694                     break;
15695                 case 1:
15696                 case 2:
15697                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15698                         v.hide();
15699                     }
15700                     break;
15701             }
15702         })
15703     },
15704     
15705     moveMonth: function(date, dir)
15706     {
15707         if (!dir) return date;
15708         var new_date = new Date(date.valueOf()),
15709         day = new_date.getUTCDate(),
15710         month = new_date.getUTCMonth(),
15711         mag = Math.abs(dir),
15712         new_month, test;
15713         dir = dir > 0 ? 1 : -1;
15714         if (mag == 1){
15715             test = dir == -1
15716             // If going back one month, make sure month is not current month
15717             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15718             ? function(){
15719                 return new_date.getUTCMonth() == month;
15720             }
15721             // If going forward one month, make sure month is as expected
15722             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15723             : function(){
15724                 return new_date.getUTCMonth() != new_month;
15725             };
15726             new_month = month + dir;
15727             new_date.setUTCMonth(new_month);
15728             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15729             if (new_month < 0 || new_month > 11)
15730                 new_month = (new_month + 12) % 12;
15731         } else {
15732             // For magnitudes >1, move one month at a time...
15733             for (var i=0; i<mag; i++)
15734                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15735                 new_date = this.moveMonth(new_date, dir);
15736             // ...then reset the day, keeping it in the new month
15737             new_month = new_date.getUTCMonth();
15738             new_date.setUTCDate(day);
15739             test = function(){
15740                 return new_month != new_date.getUTCMonth();
15741             };
15742         }
15743         // Common date-resetting loop -- if date is beyond end of month, make it
15744         // end of month
15745         while (test()){
15746             new_date.setUTCDate(--day);
15747             new_date.setUTCMonth(new_month);
15748         }
15749         return new_date;
15750     },
15751
15752     moveYear: function(date, dir)
15753     {
15754         return this.moveMonth(date, dir*12);
15755     },
15756
15757     dateWithinRange: function(date)
15758     {
15759         return date >= this.startDate && date <= this.endDate;
15760     },
15761
15762     
15763     remove: function() 
15764     {
15765         this.picker().remove();
15766     }
15767    
15768 });
15769
15770 Roo.apply(Roo.bootstrap.DateField,  {
15771     
15772     head : {
15773         tag: 'thead',
15774         cn: [
15775         {
15776             tag: 'tr',
15777             cn: [
15778             {
15779                 tag: 'th',
15780                 cls: 'prev',
15781                 html: '<i class="fa fa-arrow-left"/>'
15782             },
15783             {
15784                 tag: 'th',
15785                 cls: 'switch',
15786                 colspan: '5'
15787             },
15788             {
15789                 tag: 'th',
15790                 cls: 'next',
15791                 html: '<i class="fa fa-arrow-right"/>'
15792             }
15793
15794             ]
15795         }
15796         ]
15797     },
15798     
15799     content : {
15800         tag: 'tbody',
15801         cn: [
15802         {
15803             tag: 'tr',
15804             cn: [
15805             {
15806                 tag: 'td',
15807                 colspan: '7'
15808             }
15809             ]
15810         }
15811         ]
15812     },
15813     
15814     footer : {
15815         tag: 'tfoot',
15816         cn: [
15817         {
15818             tag: 'tr',
15819             cn: [
15820             {
15821                 tag: 'th',
15822                 colspan: '7',
15823                 cls: 'today'
15824             }
15825                     
15826             ]
15827         }
15828         ]
15829     },
15830     
15831     dates:{
15832         en: {
15833             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15834             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15835             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15836             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15837             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15838             today: "Today"
15839         }
15840     },
15841     
15842     modes: [
15843     {
15844         clsName: 'days',
15845         navFnc: 'Month',
15846         navStep: 1
15847     },
15848     {
15849         clsName: 'months',
15850         navFnc: 'FullYear',
15851         navStep: 1
15852     },
15853     {
15854         clsName: 'years',
15855         navFnc: 'FullYear',
15856         navStep: 10
15857     }]
15858 });
15859
15860 Roo.apply(Roo.bootstrap.DateField,  {
15861   
15862     template : {
15863         tag: 'div',
15864         cls: 'datepicker dropdown-menu roo-dynamic',
15865         cn: [
15866         {
15867             tag: 'div',
15868             cls: 'datepicker-days',
15869             cn: [
15870             {
15871                 tag: 'table',
15872                 cls: 'table-condensed',
15873                 cn:[
15874                 Roo.bootstrap.DateField.head,
15875                 {
15876                     tag: 'tbody'
15877                 },
15878                 Roo.bootstrap.DateField.footer
15879                 ]
15880             }
15881             ]
15882         },
15883         {
15884             tag: 'div',
15885             cls: 'datepicker-months',
15886             cn: [
15887             {
15888                 tag: 'table',
15889                 cls: 'table-condensed',
15890                 cn:[
15891                 Roo.bootstrap.DateField.head,
15892                 Roo.bootstrap.DateField.content,
15893                 Roo.bootstrap.DateField.footer
15894                 ]
15895             }
15896             ]
15897         },
15898         {
15899             tag: 'div',
15900             cls: 'datepicker-years',
15901             cn: [
15902             {
15903                 tag: 'table',
15904                 cls: 'table-condensed',
15905                 cn:[
15906                 Roo.bootstrap.DateField.head,
15907                 Roo.bootstrap.DateField.content,
15908                 Roo.bootstrap.DateField.footer
15909                 ]
15910             }
15911             ]
15912         }
15913         ]
15914     }
15915 });
15916
15917  
15918
15919  /*
15920  * - LGPL
15921  *
15922  * TimeField
15923  * 
15924  */
15925
15926 /**
15927  * @class Roo.bootstrap.TimeField
15928  * @extends Roo.bootstrap.Input
15929  * Bootstrap DateField class
15930  * 
15931  * 
15932  * @constructor
15933  * Create a new TimeField
15934  * @param {Object} config The config object
15935  */
15936
15937 Roo.bootstrap.TimeField = function(config){
15938     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15939     this.addEvents({
15940             /**
15941              * @event show
15942              * Fires when this field show.
15943              * @param {Roo.bootstrap.DateField} thisthis
15944              * @param {Mixed} date The date value
15945              */
15946             show : true,
15947             /**
15948              * @event show
15949              * Fires when this field hide.
15950              * @param {Roo.bootstrap.DateField} this
15951              * @param {Mixed} date The date value
15952              */
15953             hide : true,
15954             /**
15955              * @event select
15956              * Fires when select a date.
15957              * @param {Roo.bootstrap.DateField} this
15958              * @param {Mixed} date The date value
15959              */
15960             select : true
15961         });
15962 };
15963
15964 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
15965     
15966     /**
15967      * @cfg {String} format
15968      * The default time format string which can be overriden for localization support.  The format must be
15969      * valid according to {@link Date#parseDate} (defaults to 'H:i').
15970      */
15971     format : "H:i",
15972        
15973     onRender: function(ct, position)
15974     {
15975         
15976         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15977                 
15978         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15979         
15980         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15981         
15982         this.pop = this.picker().select('>.datepicker-time',true).first();
15983         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15984         
15985         this.picker().on('mousedown', this.onMousedown, this);
15986         this.picker().on('click', this.onClick, this);
15987         
15988         this.picker().addClass('datepicker-dropdown');
15989     
15990         this.fillTime();
15991         this.update();
15992             
15993         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
15994         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
15995         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
15996         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
15997         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
15998         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
15999
16000     },
16001     
16002     fireKey: function(e){
16003         if (!this.picker().isVisible()){
16004             if (e.keyCode == 27) { // allow escape to hide and re-show picker
16005                 this.show();
16006             }
16007             return;
16008         }
16009
16010         e.preventDefault();
16011         
16012         switch(e.keyCode){
16013             case 27: // escape
16014                 this.hide();
16015                 break;
16016             case 37: // left
16017             case 39: // right
16018                 this.onTogglePeriod();
16019                 break;
16020             case 38: // up
16021                 this.onIncrementMinutes();
16022                 break;
16023             case 40: // down
16024                 this.onDecrementMinutes();
16025                 break;
16026             case 13: // enter
16027             case 9: // tab
16028                 this.setTime();
16029                 break;
16030         }
16031     },
16032     
16033     onClick: function(e) {
16034         e.stopPropagation();
16035         e.preventDefault();
16036     },
16037     
16038     picker : function()
16039     {
16040         return this.el.select('.datepicker', true).first();
16041     },
16042     
16043     fillTime: function()
16044     {    
16045         var time = this.pop.select('tbody', true).first();
16046         
16047         time.dom.innerHTML = '';
16048         
16049         time.createChild({
16050             tag: 'tr',
16051             cn: [
16052                 {
16053                     tag: 'td',
16054                     cn: [
16055                         {
16056                             tag: 'a',
16057                             href: '#',
16058                             cls: 'btn',
16059                             cn: [
16060                                 {
16061                                     tag: 'span',
16062                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
16063                                 }
16064                             ]
16065                         } 
16066                     ]
16067                 },
16068                 {
16069                     tag: 'td',
16070                     cls: 'separator'
16071                 },
16072                 {
16073                     tag: 'td',
16074                     cn: [
16075                         {
16076                             tag: 'a',
16077                             href: '#',
16078                             cls: 'btn',
16079                             cn: [
16080                                 {
16081                                     tag: 'span',
16082                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
16083                                 }
16084                             ]
16085                         }
16086                     ]
16087                 },
16088                 {
16089                     tag: 'td',
16090                     cls: 'separator'
16091                 }
16092             ]
16093         });
16094         
16095         time.createChild({
16096             tag: 'tr',
16097             cn: [
16098                 {
16099                     tag: 'td',
16100                     cn: [
16101                         {
16102                             tag: 'span',
16103                             cls: 'timepicker-hour',
16104                             html: '00'
16105                         }  
16106                     ]
16107                 },
16108                 {
16109                     tag: 'td',
16110                     cls: 'separator',
16111                     html: ':'
16112                 },
16113                 {
16114                     tag: 'td',
16115                     cn: [
16116                         {
16117                             tag: 'span',
16118                             cls: 'timepicker-minute',
16119                             html: '00'
16120                         }  
16121                     ]
16122                 },
16123                 {
16124                     tag: 'td',
16125                     cls: 'separator'
16126                 },
16127                 {
16128                     tag: 'td',
16129                     cn: [
16130                         {
16131                             tag: 'button',
16132                             type: 'button',
16133                             cls: 'btn btn-primary period',
16134                             html: 'AM'
16135                             
16136                         }
16137                     ]
16138                 }
16139             ]
16140         });
16141         
16142         time.createChild({
16143             tag: 'tr',
16144             cn: [
16145                 {
16146                     tag: 'td',
16147                     cn: [
16148                         {
16149                             tag: 'a',
16150                             href: '#',
16151                             cls: 'btn',
16152                             cn: [
16153                                 {
16154                                     tag: 'span',
16155                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
16156                                 }
16157                             ]
16158                         }
16159                     ]
16160                 },
16161                 {
16162                     tag: 'td',
16163                     cls: 'separator'
16164                 },
16165                 {
16166                     tag: 'td',
16167                     cn: [
16168                         {
16169                             tag: 'a',
16170                             href: '#',
16171                             cls: 'btn',
16172                             cn: [
16173                                 {
16174                                     tag: 'span',
16175                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
16176                                 }
16177                             ]
16178                         }
16179                     ]
16180                 },
16181                 {
16182                     tag: 'td',
16183                     cls: 'separator'
16184                 }
16185             ]
16186         });
16187         
16188     },
16189     
16190     update: function()
16191     {
16192         
16193         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16194         
16195         this.fill();
16196     },
16197     
16198     fill: function() 
16199     {
16200         var hours = this.time.getHours();
16201         var minutes = this.time.getMinutes();
16202         var period = 'AM';
16203         
16204         if(hours > 11){
16205             period = 'PM';
16206         }
16207         
16208         if(hours == 0){
16209             hours = 12;
16210         }
16211         
16212         
16213         if(hours > 12){
16214             hours = hours - 12;
16215         }
16216         
16217         if(hours < 10){
16218             hours = '0' + hours;
16219         }
16220         
16221         if(minutes < 10){
16222             minutes = '0' + minutes;
16223         }
16224         
16225         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16226         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16227         this.pop.select('button', true).first().dom.innerHTML = period;
16228         
16229     },
16230     
16231     place: function()
16232     {   
16233         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16234         
16235         var cls = ['bottom'];
16236         
16237         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16238             cls.pop();
16239             cls.push('top');
16240         }
16241         
16242         cls.push('right');
16243         
16244         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16245             cls.pop();
16246             cls.push('left');
16247         }
16248         
16249         this.picker().addClass(cls.join('-'));
16250         
16251         var _this = this;
16252         
16253         Roo.each(cls, function(c){
16254             if(c == 'bottom'){
16255                 _this.picker().setTop(_this.inputEl().getHeight());
16256                 return;
16257             }
16258             if(c == 'top'){
16259                 _this.picker().setTop(0 - _this.picker().getHeight());
16260                 return;
16261             }
16262             
16263             if(c == 'left'){
16264                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16265                 return;
16266             }
16267             if(c == 'right'){
16268                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16269                 return;
16270             }
16271         });
16272         
16273     },
16274   
16275     onFocus : function()
16276     {
16277         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16278         this.show();
16279     },
16280     
16281     onBlur : function()
16282     {
16283         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16284         this.hide();
16285     },
16286     
16287     show : function()
16288     {
16289         this.picker().show();
16290         this.pop.show();
16291         this.update();
16292         this.place();
16293         
16294         this.fireEvent('show', this, this.date);
16295     },
16296     
16297     hide : function()
16298     {
16299         this.picker().hide();
16300         this.pop.hide();
16301         
16302         this.fireEvent('hide', this, this.date);
16303     },
16304     
16305     setTime : function()
16306     {
16307         this.hide();
16308         this.setValue(this.time.format(this.format));
16309         
16310         this.fireEvent('select', this, this.date);
16311         
16312         
16313     },
16314     
16315     onMousedown: function(e){
16316         e.stopPropagation();
16317         e.preventDefault();
16318     },
16319     
16320     onIncrementHours: function()
16321     {
16322         Roo.log('onIncrementHours');
16323         this.time = this.time.add(Date.HOUR, 1);
16324         this.update();
16325         
16326     },
16327     
16328     onDecrementHours: function()
16329     {
16330         Roo.log('onDecrementHours');
16331         this.time = this.time.add(Date.HOUR, -1);
16332         this.update();
16333     },
16334     
16335     onIncrementMinutes: function()
16336     {
16337         Roo.log('onIncrementMinutes');
16338         this.time = this.time.add(Date.MINUTE, 1);
16339         this.update();
16340     },
16341     
16342     onDecrementMinutes: function()
16343     {
16344         Roo.log('onDecrementMinutes');
16345         this.time = this.time.add(Date.MINUTE, -1);
16346         this.update();
16347     },
16348     
16349     onTogglePeriod: function()
16350     {
16351         Roo.log('onTogglePeriod');
16352         this.time = this.time.add(Date.HOUR, 12);
16353         this.update();
16354     }
16355     
16356    
16357 });
16358
16359 Roo.apply(Roo.bootstrap.TimeField,  {
16360     
16361     content : {
16362         tag: 'tbody',
16363         cn: [
16364             {
16365                 tag: 'tr',
16366                 cn: [
16367                 {
16368                     tag: 'td',
16369                     colspan: '7'
16370                 }
16371                 ]
16372             }
16373         ]
16374     },
16375     
16376     footer : {
16377         tag: 'tfoot',
16378         cn: [
16379             {
16380                 tag: 'tr',
16381                 cn: [
16382                 {
16383                     tag: 'th',
16384                     colspan: '7',
16385                     cls: '',
16386                     cn: [
16387                         {
16388                             tag: 'button',
16389                             cls: 'btn btn-info ok',
16390                             html: 'OK'
16391                         }
16392                     ]
16393                 }
16394
16395                 ]
16396             }
16397         ]
16398     }
16399 });
16400
16401 Roo.apply(Roo.bootstrap.TimeField,  {
16402   
16403     template : {
16404         tag: 'div',
16405         cls: 'datepicker dropdown-menu',
16406         cn: [
16407             {
16408                 tag: 'div',
16409                 cls: 'datepicker-time',
16410                 cn: [
16411                 {
16412                     tag: 'table',
16413                     cls: 'table-condensed',
16414                     cn:[
16415                     Roo.bootstrap.TimeField.content,
16416                     Roo.bootstrap.TimeField.footer
16417                     ]
16418                 }
16419                 ]
16420             }
16421         ]
16422     }
16423 });
16424
16425  
16426
16427  /*
16428  * - LGPL
16429  *
16430  * MonthField
16431  * 
16432  */
16433
16434 /**
16435  * @class Roo.bootstrap.MonthField
16436  * @extends Roo.bootstrap.Input
16437  * Bootstrap MonthField class
16438  * 
16439  * @cfg {String} language default en
16440  * 
16441  * @constructor
16442  * Create a new MonthField
16443  * @param {Object} config The config object
16444  */
16445
16446 Roo.bootstrap.MonthField = function(config){
16447     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16448     
16449     this.addEvents({
16450         /**
16451          * @event show
16452          * Fires when this field show.
16453          * @param {Roo.bootstrap.MonthField} this
16454          * @param {Mixed} date The date value
16455          */
16456         show : true,
16457         /**
16458          * @event show
16459          * Fires when this field hide.
16460          * @param {Roo.bootstrap.MonthField} this
16461          * @param {Mixed} date The date value
16462          */
16463         hide : true,
16464         /**
16465          * @event select
16466          * Fires when select a date.
16467          * @param {Roo.bootstrap.MonthField} this
16468          * @param {String} oldvalue The old value
16469          * @param {String} newvalue The new value
16470          */
16471         select : true
16472     });
16473 };
16474
16475 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
16476     
16477     onRender: function(ct, position)
16478     {
16479         
16480         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16481         
16482         this.language = this.language || 'en';
16483         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16484         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16485         
16486         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16487         this.isInline = false;
16488         this.isInput = true;
16489         this.component = this.el.select('.add-on', true).first() || false;
16490         this.component = (this.component && this.component.length === 0) ? false : this.component;
16491         this.hasInput = this.component && this.inputEL().length;
16492         
16493         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16494         
16495         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16496         
16497         this.picker().on('mousedown', this.onMousedown, this);
16498         this.picker().on('click', this.onClick, this);
16499         
16500         this.picker().addClass('datepicker-dropdown');
16501         
16502         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16503             v.setStyle('width', '189px');
16504         });
16505         
16506         this.fillMonths();
16507         
16508         this.update();
16509         
16510         if(this.isInline) {
16511             this.show();
16512         }
16513         
16514     },
16515     
16516     setValue: function(v, suppressEvent)
16517     {   
16518         var o = this.getValue();
16519         
16520         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16521         
16522         this.update();
16523
16524         if(suppressEvent !== true){
16525             this.fireEvent('select', this, o, v);
16526         }
16527         
16528     },
16529     
16530     getValue: function()
16531     {
16532         return this.value;
16533     },
16534     
16535     onClick: function(e) 
16536     {
16537         e.stopPropagation();
16538         e.preventDefault();
16539         
16540         var target = e.getTarget();
16541         
16542         if(target.nodeName.toLowerCase() === 'i'){
16543             target = Roo.get(target).dom.parentNode;
16544         }
16545         
16546         var nodeName = target.nodeName;
16547         var className = target.className;
16548         var html = target.innerHTML;
16549         
16550         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16551             return;
16552         }
16553         
16554         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16555         
16556         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16557         
16558         this.hide();
16559                         
16560     },
16561     
16562     picker : function()
16563     {
16564         return this.pickerEl;
16565     },
16566     
16567     fillMonths: function()
16568     {    
16569         var i = 0;
16570         var months = this.picker().select('>.datepicker-months td', true).first();
16571         
16572         months.dom.innerHTML = '';
16573         
16574         while (i < 12) {
16575             var month = {
16576                 tag: 'span',
16577                 cls: 'month',
16578                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16579             }
16580             
16581             months.createChild(month);
16582         }
16583         
16584     },
16585     
16586     update: function()
16587     {
16588         var _this = this;
16589         
16590         if(typeof(this.vIndex) == 'undefined' && this.value.length){
16591             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16592         }
16593         
16594         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16595             e.removeClass('active');
16596             
16597             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16598                 e.addClass('active');
16599             }
16600         })
16601     },
16602     
16603     place: function()
16604     {
16605         if(this.isInline) return;
16606         
16607         this.picker().removeClass(['bottom', 'top']);
16608         
16609         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16610             /*
16611              * place to the top of element!
16612              *
16613              */
16614             
16615             this.picker().addClass('top');
16616             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16617             
16618             return;
16619         }
16620         
16621         this.picker().addClass('bottom');
16622         
16623         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16624     },
16625     
16626     onFocus : function()
16627     {
16628         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16629         this.show();
16630     },
16631     
16632     onBlur : function()
16633     {
16634         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16635         
16636         var d = this.inputEl().getValue();
16637         
16638         this.setValue(d);
16639                 
16640         this.hide();
16641     },
16642     
16643     show : function()
16644     {
16645         this.picker().show();
16646         this.picker().select('>.datepicker-months', true).first().show();
16647         this.update();
16648         this.place();
16649         
16650         this.fireEvent('show', this, this.date);
16651     },
16652     
16653     hide : function()
16654     {
16655         if(this.isInline) return;
16656         this.picker().hide();
16657         this.fireEvent('hide', this, this.date);
16658         
16659     },
16660     
16661     onMousedown: function(e)
16662     {
16663         e.stopPropagation();
16664         e.preventDefault();
16665     },
16666     
16667     keyup: function(e)
16668     {
16669         Roo.bootstrap.MonthField.superclass.keyup.call(this);
16670         this.update();
16671     },
16672
16673     fireKey: function(e)
16674     {
16675         if (!this.picker().isVisible()){
16676             if (e.keyCode == 27) // allow escape to hide and re-show picker
16677                 this.show();
16678             return;
16679         }
16680         
16681         var dir;
16682         
16683         switch(e.keyCode){
16684             case 27: // escape
16685                 this.hide();
16686                 e.preventDefault();
16687                 break;
16688             case 37: // left
16689             case 39: // right
16690                 dir = e.keyCode == 37 ? -1 : 1;
16691                 
16692                 this.vIndex = this.vIndex + dir;
16693                 
16694                 if(this.vIndex < 0){
16695                     this.vIndex = 0;
16696                 }
16697                 
16698                 if(this.vIndex > 11){
16699                     this.vIndex = 11;
16700                 }
16701                 
16702                 if(isNaN(this.vIndex)){
16703                     this.vIndex = 0;
16704                 }
16705                 
16706                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16707                 
16708                 break;
16709             case 38: // up
16710             case 40: // down
16711                 
16712                 dir = e.keyCode == 38 ? -1 : 1;
16713                 
16714                 this.vIndex = this.vIndex + dir * 4;
16715                 
16716                 if(this.vIndex < 0){
16717                     this.vIndex = 0;
16718                 }
16719                 
16720                 if(this.vIndex > 11){
16721                     this.vIndex = 11;
16722                 }
16723                 
16724                 if(isNaN(this.vIndex)){
16725                     this.vIndex = 0;
16726                 }
16727                 
16728                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16729                 break;
16730                 
16731             case 13: // enter
16732                 
16733                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16734                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16735                 }
16736                 
16737                 this.hide();
16738                 e.preventDefault();
16739                 break;
16740             case 9: // tab
16741                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16742                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16743                 }
16744                 this.hide();
16745                 break;
16746             case 16: // shift
16747             case 17: // ctrl
16748             case 18: // alt
16749                 break;
16750             default :
16751                 this.hide();
16752                 
16753         }
16754     },
16755     
16756     remove: function() 
16757     {
16758         this.picker().remove();
16759     }
16760    
16761 });
16762
16763 Roo.apply(Roo.bootstrap.MonthField,  {
16764     
16765     content : {
16766         tag: 'tbody',
16767         cn: [
16768         {
16769             tag: 'tr',
16770             cn: [
16771             {
16772                 tag: 'td',
16773                 colspan: '7'
16774             }
16775             ]
16776         }
16777         ]
16778     },
16779     
16780     dates:{
16781         en: {
16782             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16783             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16784         }
16785     }
16786 });
16787
16788 Roo.apply(Roo.bootstrap.MonthField,  {
16789   
16790     template : {
16791         tag: 'div',
16792         cls: 'datepicker dropdown-menu roo-dynamic',
16793         cn: [
16794             {
16795                 tag: 'div',
16796                 cls: 'datepicker-months',
16797                 cn: [
16798                 {
16799                     tag: 'table',
16800                     cls: 'table-condensed',
16801                     cn:[
16802                         Roo.bootstrap.DateField.content
16803                     ]
16804                 }
16805                 ]
16806             }
16807         ]
16808     }
16809 });
16810
16811  
16812
16813  
16814  /*
16815  * - LGPL
16816  *
16817  * CheckBox
16818  * 
16819  */
16820
16821 /**
16822  * @class Roo.bootstrap.CheckBox
16823  * @extends Roo.bootstrap.Input
16824  * Bootstrap CheckBox class
16825  * 
16826  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16827  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16828  * @cfg {String} boxLabel The text that appears beside the checkbox
16829  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16830  * @cfg {Boolean} checked initnal the element
16831  * @cfg {Boolean} inline inline the element (default false)
16832  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16833  * 
16834  * @constructor
16835  * Create a new CheckBox
16836  * @param {Object} config The config object
16837  */
16838
16839 Roo.bootstrap.CheckBox = function(config){
16840     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16841    
16842     this.addEvents({
16843         /**
16844         * @event check
16845         * Fires when the element is checked or unchecked.
16846         * @param {Roo.bootstrap.CheckBox} this This input
16847         * @param {Boolean} checked The new checked value
16848         */
16849        check : true
16850     });
16851     
16852 };
16853
16854 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
16855   
16856     inputType: 'checkbox',
16857     inputValue: 1,
16858     valueOff: 0,
16859     boxLabel: false,
16860     checked: false,
16861     weight : false,
16862     inline: false,
16863     
16864     getAutoCreate : function()
16865     {
16866         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16867         
16868         var id = Roo.id();
16869         
16870         var cfg = {};
16871         
16872         cfg.cls = 'form-group ' + this.inputType; //input-group
16873         
16874         if(this.inline){
16875             cfg.cls += ' ' + this.inputType + '-inline';
16876         }
16877         
16878         var input =  {
16879             tag: 'input',
16880             id : id,
16881             type : this.inputType,
16882             value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16883             cls : 'roo-' + this.inputType, //'form-box',
16884             placeholder : this.placeholder || ''
16885             
16886         };
16887         
16888         if (this.weight) { // Validity check?
16889             cfg.cls += " " + this.inputType + "-" + this.weight;
16890         }
16891         
16892         if (this.disabled) {
16893             input.disabled=true;
16894         }
16895         
16896         if(this.checked){
16897             input.checked = this.checked;
16898         }
16899         
16900         if (this.name) {
16901             input.name = this.name;
16902         }
16903         
16904         if (this.size) {
16905             input.cls += ' input-' + this.size;
16906         }
16907         
16908         var settings=this;
16909         
16910         ['xs','sm','md','lg'].map(function(size){
16911             if (settings[size]) {
16912                 cfg.cls += ' col-' + size + '-' + settings[size];
16913             }
16914         });
16915         
16916         var inputblock = input;
16917          
16918         if (this.before || this.after) {
16919             
16920             inputblock = {
16921                 cls : 'input-group',
16922                 cn :  [] 
16923             };
16924             
16925             if (this.before) {
16926                 inputblock.cn.push({
16927                     tag :'span',
16928                     cls : 'input-group-addon',
16929                     html : this.before
16930                 });
16931             }
16932             
16933             inputblock.cn.push(input);
16934             
16935             if (this.after) {
16936                 inputblock.cn.push({
16937                     tag :'span',
16938                     cls : 'input-group-addon',
16939                     html : this.after
16940                 });
16941             }
16942             
16943         }
16944         
16945         if (align ==='left' && this.fieldLabel.length) {
16946                 Roo.log("left and has label");
16947                 cfg.cn = [
16948                     
16949                     {
16950                         tag: 'label',
16951                         'for' :  id,
16952                         cls : 'control-label col-md-' + this.labelWidth,
16953                         html : this.fieldLabel
16954                         
16955                     },
16956                     {
16957                         cls : "col-md-" + (12 - this.labelWidth), 
16958                         cn: [
16959                             inputblock
16960                         ]
16961                     }
16962                     
16963                 ];
16964         } else if ( this.fieldLabel.length) {
16965                 Roo.log(" label");
16966                 cfg.cn = [
16967                    
16968                     {
16969                         tag: this.boxLabel ? 'span' : 'label',
16970                         'for': id,
16971                         cls: 'control-label box-input-label',
16972                         //cls : 'input-group-addon',
16973                         html : this.fieldLabel
16974                         
16975                     },
16976                     
16977                     inputblock
16978                     
16979                 ];
16980
16981         } else {
16982             
16983                 Roo.log(" no label && no align");
16984                 cfg.cn = [  inputblock ] ;
16985                 
16986                 
16987         }
16988         if(this.boxLabel){
16989              var boxLabelCfg = {
16990                 tag: 'label',
16991                 //'for': id, // box label is handled by onclick - so no for...
16992                 cls: 'box-label',
16993                 html: this.boxLabel
16994             }
16995             
16996             if(this.tooltip){
16997                 boxLabelCfg.tooltip = this.tooltip;
16998             }
16999              
17000             cfg.cn.push(boxLabelCfg);
17001         }
17002         
17003         
17004        
17005         return cfg;
17006         
17007     },
17008     
17009     /**
17010      * return the real input element.
17011      */
17012     inputEl: function ()
17013     {
17014         return this.el.select('input.roo-' + this.inputType,true).first();
17015     },
17016     
17017     labelEl: function()
17018     {
17019         return this.el.select('label.control-label',true).first();
17020     },
17021     /* depricated... */
17022     
17023     label: function()
17024     {
17025         return this.labelEl();
17026     },
17027     
17028     initEvents : function()
17029     {
17030 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17031         
17032         this.inputEl().on('click', this.onClick,  this);
17033         
17034         if (this.boxLabel) { 
17035             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
17036         }
17037         
17038         this.startValue = this.getValue();
17039         
17040         if(this.groupId){
17041             Roo.bootstrap.CheckBox.register(this);
17042         }
17043     },
17044     
17045     onClick : function()
17046     {   
17047         this.setChecked(!this.checked);
17048     },
17049     
17050     setChecked : function(state,suppressEvent)
17051     {
17052         this.startValue = this.getValue();
17053         
17054         if(this.inputType == 'radio'){
17055             
17056             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17057                 e.dom.checked = false;
17058             });
17059             
17060             this.inputEl().dom.checked = true;
17061             
17062             this.inputEl().dom.value = this.inputValue;
17063             
17064             if(suppressEvent !== true){
17065                 this.fireEvent('check', this, true);
17066             }
17067             
17068             this.validate();
17069             
17070             return;
17071         }
17072         
17073         this.checked = state;
17074         
17075         this.inputEl().dom.checked = state;
17076         
17077         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17078         
17079         if(suppressEvent !== true){
17080             this.fireEvent('check', this, state);
17081         }
17082         
17083         this.validate();
17084     },
17085     
17086     getValue : function()
17087     {
17088         if(this.inputType == 'radio'){
17089             return this.getGroupValue();
17090         }
17091         
17092         return this.inputEl().getValue();
17093         
17094     },
17095     
17096     getGroupValue : function()
17097     {
17098         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17099             return '';
17100         }
17101         
17102         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17103     },
17104     
17105     setValue : function(v,suppressEvent)
17106     {
17107         if(this.inputType == 'radio'){
17108             this.setGroupValue(v, suppressEvent);
17109             return;
17110         }
17111         
17112         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17113         
17114         this.validate();
17115     },
17116     
17117     setGroupValue : function(v, suppressEvent)
17118     {
17119         this.startValue = this.getValue();
17120         
17121         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17122             e.dom.checked = false;
17123             
17124             if(e.dom.value == v){
17125                 e.dom.checked = true;
17126             }
17127         });
17128         
17129         if(suppressEvent !== true){
17130             this.fireEvent('check', this, true);
17131         }
17132
17133         this.validate();
17134         
17135         return;
17136     },
17137     
17138     validate : function()
17139     {
17140         if(
17141                 this.disabled || 
17142                 (this.inputType == 'radio' && this.validateRadio()) ||
17143                 (this.inputType == 'checkbox' && this.validateCheckbox())
17144         ){
17145             this.markValid();
17146             return true;
17147         }
17148         
17149         this.markInvalid();
17150         return false;
17151     },
17152     
17153     validateRadio : function()
17154     {
17155         var valid = false;
17156         
17157         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17158             if(!e.dom.checked){
17159                 return;
17160             }
17161             
17162             valid = true;
17163             
17164             return false;
17165         });
17166         
17167         return valid;
17168     },
17169     
17170     validateCheckbox : function()
17171     {
17172         if(!this.groupId){
17173             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17174         }
17175         
17176         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17177         
17178         if(!group){
17179             return false;
17180         }
17181         
17182         var r = false;
17183         
17184         for(var i in group){
17185             if(r){
17186                 break;
17187             }
17188             
17189             r = (group[i].getValue() == group[i].inputValue) ? true : false;
17190         }
17191         
17192         return r;
17193     },
17194     
17195     /**
17196      * Mark this field as valid
17197      */
17198     markValid : function()
17199     {
17200         if(this.allowBlank){
17201             return;
17202         }
17203         
17204         var _this = this;
17205         
17206         this.fireEvent('valid', this);
17207         
17208         if(this.inputType == 'radio'){
17209             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17210                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17211                 e.findParent('.form-group', false, true).addClass(_this.validClass);
17212             });
17213             
17214             return;
17215         }
17216         
17217         if(!this.groupId){
17218             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17219             this.el.findParent('.form-group', false, true).addClass(this.validClass);
17220             return;
17221         }
17222         
17223         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17224             
17225         if(!group){
17226             return;
17227         }
17228         
17229         for(var i in group){
17230             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17231             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17232         }
17233     },
17234     
17235      /**
17236      * Mark this field as invalid
17237      * @param {String} msg The validation message
17238      */
17239     markInvalid : function(msg)
17240     {
17241         if(this.allowBlank){
17242             return;
17243         }
17244         
17245         var _this = this;
17246         
17247         this.fireEvent('invalid', this, msg);
17248         
17249         if(this.inputType == 'radio'){
17250             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17251                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17252                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17253             });
17254             
17255             return;
17256         }
17257         
17258         if(!this.groupId){
17259             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17260             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17261             return;
17262         }
17263         
17264         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17265             
17266         if(!group){
17267             return;
17268         }
17269         
17270         for(var i in group){
17271             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17272             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17273         }
17274         
17275     }
17276     
17277 });
17278
17279 Roo.apply(Roo.bootstrap.CheckBox, {
17280     
17281     groups: {},
17282     
17283      /**
17284     * register a CheckBox Group
17285     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17286     */
17287     register : function(checkbox)
17288     {
17289         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17290             this.groups[checkbox.groupId] = {};
17291         }
17292         
17293         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17294             return;
17295         }
17296         
17297         this.groups[checkbox.groupId][checkbox.name] = checkbox;
17298         
17299     },
17300     /**
17301     * fetch a CheckBox Group based on the group ID
17302     * @param {string} the group ID
17303     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17304     */
17305     get: function(groupId) {
17306         if (typeof(this.groups[groupId]) == 'undefined') {
17307             return false;
17308         }
17309         
17310         return this.groups[groupId] ;
17311     }
17312     
17313     
17314 });
17315 /*
17316  * - LGPL
17317  *
17318  * Radio
17319  *
17320  *
17321  * not inline
17322  *<div class="radio">
17323   <label>
17324     <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17325     Option one is this and that&mdash;be sure to include why it's great
17326   </label>
17327 </div>
17328  *
17329  *
17330  *inline
17331  *<span>
17332  *<label class="radio-inline">fieldLabel</label>
17333  *<label class="radio-inline">
17334   <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17335 </label>
17336 <span>
17337  * 
17338  * 
17339  */
17340
17341 /**
17342  * @class Roo.bootstrap.Radio
17343  * @extends Roo.bootstrap.CheckBox
17344  * Bootstrap Radio class
17345
17346  * @constructor
17347  * Create a new Radio
17348  * @param {Object} config The config object
17349  */
17350
17351 Roo.bootstrap.Radio = function(config){
17352     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17353    
17354 };
17355
17356 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
17357     
17358     inputType: 'radio',
17359     inputValue: '',
17360     valueOff: '',
17361     
17362     getAutoCreate : function()
17363     {
17364         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17365         align = align || 'left'; // default...
17366         
17367         
17368         
17369         var id = Roo.id();
17370         
17371         var cfg = {
17372                 tag : this.inline ? 'span' : 'div',
17373                 cls : '',
17374                 cn : []
17375         };
17376         
17377         var inline = this.inline ? ' radio-inline' : '';
17378         
17379         var lbl = {
17380                 tag: 'label' ,
17381                 // does not need for, as we wrap the input with it..
17382                 'for' : id,
17383                 cls : 'control-label box-label' + inline,
17384                 cn : []
17385         };
17386         var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17387         
17388         var fieldLabel = {
17389             tag: 'label' ,
17390             //cls : 'control-label' + inline,
17391             html : this.fieldLabel,
17392             style : 'width:' +  labelWidth  + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17393         };
17394         
17395  
17396         
17397         
17398         var input =  {
17399             tag: 'input',
17400             id : id,
17401             type : this.inputType,
17402             //value : (!this.checked) ? this.valueOff : this.inputValue,
17403             value : this.inputValue,
17404             cls : 'roo-radio',
17405             placeholder : this.placeholder || '' // ?? needed????
17406             
17407         };
17408         if (this.weight) { // Validity check?
17409             input.cls += " radio-" + this.weight;
17410         }
17411         if (this.disabled) {
17412             input.disabled=true;
17413         }
17414         
17415         if(this.checked){
17416             input.checked = this.checked;
17417         }
17418         
17419         if (this.name) {
17420             input.name = this.name;
17421         }
17422         
17423         if (this.size) {
17424             input.cls += ' input-' + this.size;
17425         }
17426         
17427         //?? can span's inline have a width??
17428         
17429         var settings=this;
17430         ['xs','sm','md','lg'].map(function(size){
17431             if (settings[size]) {
17432                 cfg.cls += ' col-' + size + '-' + settings[size];
17433             }
17434         });
17435         
17436         var inputblock = input;
17437         
17438         if (this.before || this.after) {
17439             
17440             inputblock = {
17441                 cls : 'input-group',
17442                 tag : 'span',
17443                 cn :  [] 
17444             };
17445             if (this.before) {
17446                 inputblock.cn.push({
17447                     tag :'span',
17448                     cls : 'input-group-addon',
17449                     html : this.before
17450                 });
17451             }
17452             inputblock.cn.push(input);
17453             if (this.after) {
17454                 inputblock.cn.push({
17455                     tag :'span',
17456                     cls : 'input-group-addon',
17457                     html : this.after
17458                 });
17459             }
17460             
17461         };
17462         
17463         
17464         if (this.fieldLabel && this.fieldLabel.length) {
17465             cfg.cn.push(fieldLabel);
17466         }
17467        
17468         // normal bootstrap puts the input inside the label.
17469         // however with our styled version - it has to go after the input.
17470        
17471         //lbl.cn.push(inputblock);
17472         
17473         var lblwrap =  {
17474             tag: 'span',
17475             cls: 'radio' + inline,
17476             cn: [
17477                 inputblock,
17478                 lbl
17479             ]
17480         };
17481         
17482         cfg.cn.push( lblwrap);
17483         
17484         if(this.boxLabel){
17485             lbl.cn.push({
17486                 tag: 'span',
17487                 html: this.boxLabel
17488             })
17489         }
17490          
17491         
17492         return cfg;
17493         
17494     },
17495     
17496     initEvents : function()
17497     {
17498 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17499         
17500         this.inputEl().on('click', this.onClick,  this);
17501         if (this.boxLabel) {
17502             Roo.log('find label')
17503             this.el.select('span.radio label span',true).first().on('click', this.onClick,  this);
17504         }
17505         
17506     },
17507     
17508     inputEl: function ()
17509     {
17510         return this.el.select('input.roo-radio',true).first();
17511     },
17512     onClick : function()
17513     {   
17514         Roo.log("click");
17515         this.setChecked(true);
17516     },
17517     
17518     setChecked : function(state,suppressEvent)
17519     {
17520         if(state){
17521             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17522                 v.dom.checked = false;
17523             });
17524         }
17525         Roo.log(this.inputEl().dom);
17526         this.checked = state;
17527         this.inputEl().dom.checked = state;
17528         
17529         if(suppressEvent !== true){
17530             this.fireEvent('check', this, state);
17531         }
17532         
17533         //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17534         
17535     },
17536     
17537     getGroupValue : function()
17538     {
17539         var value = '';
17540         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17541             if(v.dom.checked == true){
17542                 value = v.dom.value;
17543             }
17544         });
17545         
17546         return value;
17547     },
17548     
17549     /**
17550      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
17551      * @return {Mixed} value The field value
17552      */
17553     getValue : function(){
17554         return this.getGroupValue();
17555     }
17556     
17557 });
17558
17559  
17560 //<script type="text/javascript">
17561
17562 /*
17563  * Based  Ext JS Library 1.1.1
17564  * Copyright(c) 2006-2007, Ext JS, LLC.
17565  * LGPL
17566  *
17567  */
17568  
17569 /**
17570  * @class Roo.HtmlEditorCore
17571  * @extends Roo.Component
17572  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17573  *
17574  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17575  */
17576
17577 Roo.HtmlEditorCore = function(config){
17578     
17579     
17580     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17581     
17582     
17583     this.addEvents({
17584         /**
17585          * @event initialize
17586          * Fires when the editor is fully initialized (including the iframe)
17587          * @param {Roo.HtmlEditorCore} this
17588          */
17589         initialize: true,
17590         /**
17591          * @event activate
17592          * Fires when the editor is first receives the focus. Any insertion must wait
17593          * until after this event.
17594          * @param {Roo.HtmlEditorCore} this
17595          */
17596         activate: true,
17597          /**
17598          * @event beforesync
17599          * Fires before the textarea is updated with content from the editor iframe. Return false
17600          * to cancel the sync.
17601          * @param {Roo.HtmlEditorCore} this
17602          * @param {String} html
17603          */
17604         beforesync: true,
17605          /**
17606          * @event beforepush
17607          * Fires before the iframe editor is updated with content from the textarea. Return false
17608          * to cancel the push.
17609          * @param {Roo.HtmlEditorCore} this
17610          * @param {String} html
17611          */
17612         beforepush: true,
17613          /**
17614          * @event sync
17615          * Fires when the textarea is updated with content from the editor iframe.
17616          * @param {Roo.HtmlEditorCore} this
17617          * @param {String} html
17618          */
17619         sync: true,
17620          /**
17621          * @event push
17622          * Fires when the iframe editor is updated with content from the textarea.
17623          * @param {Roo.HtmlEditorCore} this
17624          * @param {String} html
17625          */
17626         push: true,
17627         
17628         /**
17629          * @event editorevent
17630          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17631          * @param {Roo.HtmlEditorCore} this
17632          */
17633         editorevent: true
17634         
17635     });
17636     
17637     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17638     
17639     // defaults : white / black...
17640     this.applyBlacklists();
17641     
17642     
17643     
17644 };
17645
17646
17647 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
17648
17649
17650      /**
17651      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
17652      */
17653     
17654     owner : false,
17655     
17656      /**
17657      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17658      *                        Roo.resizable.
17659      */
17660     resizable : false,
17661      /**
17662      * @cfg {Number} height (in pixels)
17663      */   
17664     height: 300,
17665    /**
17666      * @cfg {Number} width (in pixels)
17667      */   
17668     width: 500,
17669     
17670     /**
17671      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17672      * 
17673      */
17674     stylesheets: false,
17675     
17676     // id of frame..
17677     frameId: false,
17678     
17679     // private properties
17680     validationEvent : false,
17681     deferHeight: true,
17682     initialized : false,
17683     activated : false,
17684     sourceEditMode : false,
17685     onFocus : Roo.emptyFn,
17686     iframePad:3,
17687     hideMode:'offsets',
17688     
17689     clearUp: true,
17690     
17691     // blacklist + whitelisted elements..
17692     black: false,
17693     white: false,
17694      
17695     
17696
17697     /**
17698      * Protected method that will not generally be called directly. It
17699      * is called when the editor initializes the iframe with HTML contents. Override this method if you
17700      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17701      */
17702     getDocMarkup : function(){
17703         // body styles..
17704         var st = '';
17705         
17706         // inherit styels from page...?? 
17707         if (this.stylesheets === false) {
17708             
17709             Roo.get(document.head).select('style').each(function(node) {
17710                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17711             });
17712             
17713             Roo.get(document.head).select('link').each(function(node) { 
17714                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17715             });
17716             
17717         } else if (!this.stylesheets.length) {
17718                 // simple..
17719                 st = '<style type="text/css">' +
17720                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17721                    '</style>';
17722         } else { 
17723             
17724         }
17725         
17726         st +=  '<style type="text/css">' +
17727             'IMG { cursor: pointer } ' +
17728         '</style>';
17729
17730         
17731         return '<html><head>' + st  +
17732             //<style type="text/css">' +
17733             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17734             //'</style>' +
17735             ' </head><body class="roo-htmleditor-body"></body></html>';
17736     },
17737
17738     // private
17739     onRender : function(ct, position)
17740     {
17741         var _t = this;
17742         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17743         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17744         
17745         
17746         this.el.dom.style.border = '0 none';
17747         this.el.dom.setAttribute('tabIndex', -1);
17748         this.el.addClass('x-hidden hide');
17749         
17750         
17751         
17752         if(Roo.isIE){ // fix IE 1px bogus margin
17753             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17754         }
17755        
17756         
17757         this.frameId = Roo.id();
17758         
17759          
17760         
17761         var iframe = this.owner.wrap.createChild({
17762             tag: 'iframe',
17763             cls: 'form-control', // bootstrap..
17764             id: this.frameId,
17765             name: this.frameId,
17766             frameBorder : 'no',
17767             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
17768         }, this.el
17769         );
17770         
17771         
17772         this.iframe = iframe.dom;
17773
17774          this.assignDocWin();
17775         
17776         this.doc.designMode = 'on';
17777        
17778         this.doc.open();
17779         this.doc.write(this.getDocMarkup());
17780         this.doc.close();
17781
17782         
17783         var task = { // must defer to wait for browser to be ready
17784             run : function(){
17785                 //console.log("run task?" + this.doc.readyState);
17786                 this.assignDocWin();
17787                 if(this.doc.body || this.doc.readyState == 'complete'){
17788                     try {
17789                         this.doc.designMode="on";
17790                     } catch (e) {
17791                         return;
17792                     }
17793                     Roo.TaskMgr.stop(task);
17794                     this.initEditor.defer(10, this);
17795                 }
17796             },
17797             interval : 10,
17798             duration: 10000,
17799             scope: this
17800         };
17801         Roo.TaskMgr.start(task);
17802
17803     },
17804
17805     // private
17806     onResize : function(w, h)
17807     {
17808          Roo.log('resize: ' +w + ',' + h );
17809         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17810         if(!this.iframe){
17811             return;
17812         }
17813         if(typeof w == 'number'){
17814             
17815             this.iframe.style.width = w + 'px';
17816         }
17817         if(typeof h == 'number'){
17818             
17819             this.iframe.style.height = h + 'px';
17820             if(this.doc){
17821                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17822             }
17823         }
17824         
17825     },
17826
17827     /**
17828      * Toggles the editor between standard and source edit mode.
17829      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17830      */
17831     toggleSourceEdit : function(sourceEditMode){
17832         
17833         this.sourceEditMode = sourceEditMode === true;
17834         
17835         if(this.sourceEditMode){
17836  
17837             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
17838             
17839         }else{
17840             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17841             //this.iframe.className = '';
17842             this.deferFocus();
17843         }
17844         //this.setSize(this.owner.wrap.getSize());
17845         //this.fireEvent('editmodechange', this, this.sourceEditMode);
17846     },
17847
17848     
17849   
17850
17851     /**
17852      * Protected method that will not generally be called directly. If you need/want
17853      * custom HTML cleanup, this is the method you should override.
17854      * @param {String} html The HTML to be cleaned
17855      * return {String} The cleaned HTML
17856      */
17857     cleanHtml : function(html){
17858         html = String(html);
17859         if(html.length > 5){
17860             if(Roo.isSafari){ // strip safari nonsense
17861                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17862             }
17863         }
17864         if(html == '&nbsp;'){
17865             html = '';
17866         }
17867         return html;
17868     },
17869
17870     /**
17871      * HTML Editor -> Textarea
17872      * Protected method that will not generally be called directly. Syncs the contents
17873      * of the editor iframe with the textarea.
17874      */
17875     syncValue : function(){
17876         if(this.initialized){
17877             var bd = (this.doc.body || this.doc.documentElement);
17878             //this.cleanUpPaste(); -- this is done else where and causes havoc..
17879             var html = bd.innerHTML;
17880             if(Roo.isSafari){
17881                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17882                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17883                 if(m && m[1]){
17884                     html = '<div style="'+m[0]+'">' + html + '</div>';
17885                 }
17886             }
17887             html = this.cleanHtml(html);
17888             // fix up the special chars.. normaly like back quotes in word...
17889             // however we do not want to do this with chinese..
17890             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17891                 var cc = b.charCodeAt();
17892                 if (
17893                     (cc >= 0x4E00 && cc < 0xA000 ) ||
17894                     (cc >= 0x3400 && cc < 0x4E00 ) ||
17895                     (cc >= 0xf900 && cc < 0xfb00 )
17896                 ) {
17897                         return b;
17898                 }
17899                 return "&#"+cc+";" 
17900             });
17901             if(this.owner.fireEvent('beforesync', this, html) !== false){
17902                 this.el.dom.value = html;
17903                 this.owner.fireEvent('sync', this, html);
17904             }
17905         }
17906     },
17907
17908     /**
17909      * Protected method that will not generally be called directly. Pushes the value of the textarea
17910      * into the iframe editor.
17911      */
17912     pushValue : function(){
17913         if(this.initialized){
17914             var v = this.el.dom.value.trim();
17915             
17916 //            if(v.length < 1){
17917 //                v = '&#160;';
17918 //            }
17919             
17920             if(this.owner.fireEvent('beforepush', this, v) !== false){
17921                 var d = (this.doc.body || this.doc.documentElement);
17922                 d.innerHTML = v;
17923                 this.cleanUpPaste();
17924                 this.el.dom.value = d.innerHTML;
17925                 this.owner.fireEvent('push', this, v);
17926             }
17927         }
17928     },
17929
17930     // private
17931     deferFocus : function(){
17932         this.focus.defer(10, this);
17933     },
17934
17935     // doc'ed in Field
17936     focus : function(){
17937         if(this.win && !this.sourceEditMode){
17938             this.win.focus();
17939         }else{
17940             this.el.focus();
17941         }
17942     },
17943     
17944     assignDocWin: function()
17945     {
17946         var iframe = this.iframe;
17947         
17948          if(Roo.isIE){
17949             this.doc = iframe.contentWindow.document;
17950             this.win = iframe.contentWindow;
17951         } else {
17952 //            if (!Roo.get(this.frameId)) {
17953 //                return;
17954 //            }
17955 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17956 //            this.win = Roo.get(this.frameId).dom.contentWindow;
17957             
17958             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17959                 return;
17960             }
17961             
17962             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17963             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17964         }
17965     },
17966     
17967     // private
17968     initEditor : function(){
17969         //console.log("INIT EDITOR");
17970         this.assignDocWin();
17971         
17972         
17973         
17974         this.doc.designMode="on";
17975         this.doc.open();
17976         this.doc.write(this.getDocMarkup());
17977         this.doc.close();
17978         
17979         var dbody = (this.doc.body || this.doc.documentElement);
17980         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17981         // this copies styles from the containing element into thsi one..
17982         // not sure why we need all of this..
17983         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17984         
17985         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17986         //ss['background-attachment'] = 'fixed'; // w3c
17987         dbody.bgProperties = 'fixed'; // ie
17988         //Roo.DomHelper.applyStyles(dbody, ss);
17989         Roo.EventManager.on(this.doc, {
17990             //'mousedown': this.onEditorEvent,
17991             'mouseup': this.onEditorEvent,
17992             'dblclick': this.onEditorEvent,
17993             'click': this.onEditorEvent,
17994             'keyup': this.onEditorEvent,
17995             buffer:100,
17996             scope: this
17997         });
17998         if(Roo.isGecko){
17999             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18000         }
18001         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18002             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18003         }
18004         this.initialized = true;
18005
18006         this.owner.fireEvent('initialize', this);
18007         this.pushValue();
18008     },
18009
18010     // private
18011     onDestroy : function(){
18012         
18013         
18014         
18015         if(this.rendered){
18016             
18017             //for (var i =0; i < this.toolbars.length;i++) {
18018             //    // fixme - ask toolbars for heights?
18019             //    this.toolbars[i].onDestroy();
18020            // }
18021             
18022             //this.wrap.dom.innerHTML = '';
18023             //this.wrap.remove();
18024         }
18025     },
18026
18027     // private
18028     onFirstFocus : function(){
18029         
18030         this.assignDocWin();
18031         
18032         
18033         this.activated = true;
18034          
18035     
18036         if(Roo.isGecko){ // prevent silly gecko errors
18037             this.win.focus();
18038             var s = this.win.getSelection();
18039             if(!s.focusNode || s.focusNode.nodeType != 3){
18040                 var r = s.getRangeAt(0);
18041                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18042                 r.collapse(true);
18043                 this.deferFocus();
18044             }
18045             try{
18046                 this.execCmd('useCSS', true);
18047                 this.execCmd('styleWithCSS', false);
18048             }catch(e){}
18049         }
18050         this.owner.fireEvent('activate', this);
18051     },
18052
18053     // private
18054     adjustFont: function(btn){
18055         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18056         //if(Roo.isSafari){ // safari
18057         //    adjust *= 2;
18058        // }
18059         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18060         if(Roo.isSafari){ // safari
18061             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18062             v =  (v < 10) ? 10 : v;
18063             v =  (v > 48) ? 48 : v;
18064             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18065             
18066         }
18067         
18068         
18069         v = Math.max(1, v+adjust);
18070         
18071         this.execCmd('FontSize', v  );
18072     },
18073
18074     onEditorEvent : function(e){
18075         this.owner.fireEvent('editorevent', this, e);
18076       //  this.updateToolbar();
18077         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18078     },
18079
18080     insertTag : function(tg)
18081     {
18082         // could be a bit smarter... -> wrap the current selected tRoo..
18083         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18084             
18085             range = this.createRange(this.getSelection());
18086             var wrappingNode = this.doc.createElement(tg.toLowerCase());
18087             wrappingNode.appendChild(range.extractContents());
18088             range.insertNode(wrappingNode);
18089
18090             return;
18091             
18092             
18093             
18094         }
18095         this.execCmd("formatblock",   tg);
18096         
18097     },
18098     
18099     insertText : function(txt)
18100     {
18101         
18102         
18103         var range = this.createRange();
18104         range.deleteContents();
18105                //alert(Sender.getAttribute('label'));
18106                
18107         range.insertNode(this.doc.createTextNode(txt));
18108     } ,
18109     
18110      
18111
18112     /**
18113      * Executes a Midas editor command on the editor document and performs necessary focus and
18114      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18115      * @param {String} cmd The Midas command
18116      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18117      */
18118     relayCmd : function(cmd, value){
18119         this.win.focus();
18120         this.execCmd(cmd, value);
18121         this.owner.fireEvent('editorevent', this);
18122         //this.updateToolbar();
18123         this.owner.deferFocus();
18124     },
18125
18126     /**
18127      * Executes a Midas editor command directly on the editor document.
18128      * For visual commands, you should use {@link #relayCmd} instead.
18129      * <b>This should only be called after the editor is initialized.</b>
18130      * @param {String} cmd The Midas command
18131      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18132      */
18133     execCmd : function(cmd, value){
18134         this.doc.execCommand(cmd, false, value === undefined ? null : value);
18135         this.syncValue();
18136     },
18137  
18138  
18139    
18140     /**
18141      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18142      * to insert tRoo.
18143      * @param {String} text | dom node.. 
18144      */
18145     insertAtCursor : function(text)
18146     {
18147         
18148         
18149         
18150         if(!this.activated){
18151             return;
18152         }
18153         /*
18154         if(Roo.isIE){
18155             this.win.focus();
18156             var r = this.doc.selection.createRange();
18157             if(r){
18158                 r.collapse(true);
18159                 r.pasteHTML(text);
18160                 this.syncValue();
18161                 this.deferFocus();
18162             
18163             }
18164             return;
18165         }
18166         */
18167         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18168             this.win.focus();
18169             
18170             
18171             // from jquery ui (MIT licenced)
18172             var range, node;
18173             var win = this.win;
18174             
18175             if (win.getSelection && win.getSelection().getRangeAt) {
18176                 range = win.getSelection().getRangeAt(0);
18177                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18178                 range.insertNode(node);
18179             } else if (win.document.selection && win.document.selection.createRange) {
18180                 // no firefox support
18181                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18182                 win.document.selection.createRange().pasteHTML(txt);
18183             } else {
18184                 // no firefox support
18185                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18186                 this.execCmd('InsertHTML', txt);
18187             } 
18188             
18189             this.syncValue();
18190             
18191             this.deferFocus();
18192         }
18193     },
18194  // private
18195     mozKeyPress : function(e){
18196         if(e.ctrlKey){
18197             var c = e.getCharCode(), cmd;
18198           
18199             if(c > 0){
18200                 c = String.fromCharCode(c).toLowerCase();
18201                 switch(c){
18202                     case 'b':
18203                         cmd = 'bold';
18204                         break;
18205                     case 'i':
18206                         cmd = 'italic';
18207                         break;
18208                     
18209                     case 'u':
18210                         cmd = 'underline';
18211                         break;
18212                     
18213                     case 'v':
18214                         this.cleanUpPaste.defer(100, this);
18215                         return;
18216                         
18217                 }
18218                 if(cmd){
18219                     this.win.focus();
18220                     this.execCmd(cmd);
18221                     this.deferFocus();
18222                     e.preventDefault();
18223                 }
18224                 
18225             }
18226         }
18227     },
18228
18229     // private
18230     fixKeys : function(){ // load time branching for fastest keydown performance
18231         if(Roo.isIE){
18232             return function(e){
18233                 var k = e.getKey(), r;
18234                 if(k == e.TAB){
18235                     e.stopEvent();
18236                     r = this.doc.selection.createRange();
18237                     if(r){
18238                         r.collapse(true);
18239                         r.pasteHTML('&#160;&#160;&#160;&#160;');
18240                         this.deferFocus();
18241                     }
18242                     return;
18243                 }
18244                 
18245                 if(k == e.ENTER){
18246                     r = this.doc.selection.createRange();
18247                     if(r){
18248                         var target = r.parentElement();
18249                         if(!target || target.tagName.toLowerCase() != 'li'){
18250                             e.stopEvent();
18251                             r.pasteHTML('<br />');
18252                             r.collapse(false);
18253                             r.select();
18254                         }
18255                     }
18256                 }
18257                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18258                     this.cleanUpPaste.defer(100, this);
18259                     return;
18260                 }
18261                 
18262                 
18263             };
18264         }else if(Roo.isOpera){
18265             return function(e){
18266                 var k = e.getKey();
18267                 if(k == e.TAB){
18268                     e.stopEvent();
18269                     this.win.focus();
18270                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
18271                     this.deferFocus();
18272                 }
18273                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18274                     this.cleanUpPaste.defer(100, this);
18275                     return;
18276                 }
18277                 
18278             };
18279         }else if(Roo.isSafari){
18280             return function(e){
18281                 var k = e.getKey();
18282                 
18283                 if(k == e.TAB){
18284                     e.stopEvent();
18285                     this.execCmd('InsertText','\t');
18286                     this.deferFocus();
18287                     return;
18288                 }
18289                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18290                     this.cleanUpPaste.defer(100, this);
18291                     return;
18292                 }
18293                 
18294              };
18295         }
18296     }(),
18297     
18298     getAllAncestors: function()
18299     {
18300         var p = this.getSelectedNode();
18301         var a = [];
18302         if (!p) {
18303             a.push(p); // push blank onto stack..
18304             p = this.getParentElement();
18305         }
18306         
18307         
18308         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18309             a.push(p);
18310             p = p.parentNode;
18311         }
18312         a.push(this.doc.body);
18313         return a;
18314     },
18315     lastSel : false,
18316     lastSelNode : false,
18317     
18318     
18319     getSelection : function() 
18320     {
18321         this.assignDocWin();
18322         return Roo.isIE ? this.doc.selection : this.win.getSelection();
18323     },
18324     
18325     getSelectedNode: function() 
18326     {
18327         // this may only work on Gecko!!!
18328         
18329         // should we cache this!!!!
18330         
18331         
18332         
18333          
18334         var range = this.createRange(this.getSelection()).cloneRange();
18335         
18336         if (Roo.isIE) {
18337             var parent = range.parentElement();
18338             while (true) {
18339                 var testRange = range.duplicate();
18340                 testRange.moveToElementText(parent);
18341                 if (testRange.inRange(range)) {
18342                     break;
18343                 }
18344                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18345                     break;
18346                 }
18347                 parent = parent.parentElement;
18348             }
18349             return parent;
18350         }
18351         
18352         // is ancestor a text element.
18353         var ac =  range.commonAncestorContainer;
18354         if (ac.nodeType == 3) {
18355             ac = ac.parentNode;
18356         }
18357         
18358         var ar = ac.childNodes;
18359          
18360         var nodes = [];
18361         var other_nodes = [];
18362         var has_other_nodes = false;
18363         for (var i=0;i<ar.length;i++) {
18364             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
18365                 continue;
18366             }
18367             // fullly contained node.
18368             
18369             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18370                 nodes.push(ar[i]);
18371                 continue;
18372             }
18373             
18374             // probably selected..
18375             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18376                 other_nodes.push(ar[i]);
18377                 continue;
18378             }
18379             // outer..
18380             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
18381                 continue;
18382             }
18383             
18384             
18385             has_other_nodes = true;
18386         }
18387         if (!nodes.length && other_nodes.length) {
18388             nodes= other_nodes;
18389         }
18390         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18391             return false;
18392         }
18393         
18394         return nodes[0];
18395     },
18396     createRange: function(sel)
18397     {
18398         // this has strange effects when using with 
18399         // top toolbar - not sure if it's a great idea.
18400         //this.editor.contentWindow.focus();
18401         if (typeof sel != "undefined") {
18402             try {
18403                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18404             } catch(e) {
18405                 return this.doc.createRange();
18406             }
18407         } else {
18408             return this.doc.createRange();
18409         }
18410     },
18411     getParentElement: function()
18412     {
18413         
18414         this.assignDocWin();
18415         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18416         
18417         var range = this.createRange(sel);
18418          
18419         try {
18420             var p = range.commonAncestorContainer;
18421             while (p.nodeType == 3) { // text node
18422                 p = p.parentNode;
18423             }
18424             return p;
18425         } catch (e) {
18426             return null;
18427         }
18428     
18429     },
18430     /***
18431      *
18432      * Range intersection.. the hard stuff...
18433      *  '-1' = before
18434      *  '0' = hits..
18435      *  '1' = after.
18436      *         [ -- selected range --- ]
18437      *   [fail]                        [fail]
18438      *
18439      *    basically..
18440      *      if end is before start or  hits it. fail.
18441      *      if start is after end or hits it fail.
18442      *
18443      *   if either hits (but other is outside. - then it's not 
18444      *   
18445      *    
18446      **/
18447     
18448     
18449     // @see http://www.thismuchiknow.co.uk/?p=64.
18450     rangeIntersectsNode : function(range, node)
18451     {
18452         var nodeRange = node.ownerDocument.createRange();
18453         try {
18454             nodeRange.selectNode(node);
18455         } catch (e) {
18456             nodeRange.selectNodeContents(node);
18457         }
18458     
18459         var rangeStartRange = range.cloneRange();
18460         rangeStartRange.collapse(true);
18461     
18462         var rangeEndRange = range.cloneRange();
18463         rangeEndRange.collapse(false);
18464     
18465         var nodeStartRange = nodeRange.cloneRange();
18466         nodeStartRange.collapse(true);
18467     
18468         var nodeEndRange = nodeRange.cloneRange();
18469         nodeEndRange.collapse(false);
18470     
18471         return rangeStartRange.compareBoundaryPoints(
18472                  Range.START_TO_START, nodeEndRange) == -1 &&
18473                rangeEndRange.compareBoundaryPoints(
18474                  Range.START_TO_START, nodeStartRange) == 1;
18475         
18476          
18477     },
18478     rangeCompareNode : function(range, node)
18479     {
18480         var nodeRange = node.ownerDocument.createRange();
18481         try {
18482             nodeRange.selectNode(node);
18483         } catch (e) {
18484             nodeRange.selectNodeContents(node);
18485         }
18486         
18487         
18488         range.collapse(true);
18489     
18490         nodeRange.collapse(true);
18491      
18492         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18493         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
18494          
18495         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18496         
18497         var nodeIsBefore   =  ss == 1;
18498         var nodeIsAfter    = ee == -1;
18499         
18500         if (nodeIsBefore && nodeIsAfter)
18501             return 0; // outer
18502         if (!nodeIsBefore && nodeIsAfter)
18503             return 1; //right trailed.
18504         
18505         if (nodeIsBefore && !nodeIsAfter)
18506             return 2;  // left trailed.
18507         // fully contined.
18508         return 3;
18509     },
18510
18511     // private? - in a new class?
18512     cleanUpPaste :  function()
18513     {
18514         // cleans up the whole document..
18515         Roo.log('cleanuppaste');
18516         
18517         this.cleanUpChildren(this.doc.body);
18518         var clean = this.cleanWordChars(this.doc.body.innerHTML);
18519         if (clean != this.doc.body.innerHTML) {
18520             this.doc.body.innerHTML = clean;
18521         }
18522         
18523     },
18524     
18525     cleanWordChars : function(input) {// change the chars to hex code
18526         var he = Roo.HtmlEditorCore;
18527         
18528         var output = input;
18529         Roo.each(he.swapCodes, function(sw) { 
18530             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18531             
18532             output = output.replace(swapper, sw[1]);
18533         });
18534         
18535         return output;
18536     },
18537     
18538     
18539     cleanUpChildren : function (n)
18540     {
18541         if (!n.childNodes.length) {
18542             return;
18543         }
18544         for (var i = n.childNodes.length-1; i > -1 ; i--) {
18545            this.cleanUpChild(n.childNodes[i]);
18546         }
18547     },
18548     
18549     
18550         
18551     
18552     cleanUpChild : function (node)
18553     {
18554         var ed = this;
18555         //console.log(node);
18556         if (node.nodeName == "#text") {
18557             // clean up silly Windows -- stuff?
18558             return; 
18559         }
18560         if (node.nodeName == "#comment") {
18561             node.parentNode.removeChild(node);
18562             // clean up silly Windows -- stuff?
18563             return; 
18564         }
18565         var lcname = node.tagName.toLowerCase();
18566         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18567         // whitelist of tags..
18568         
18569         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18570             // remove node.
18571             node.parentNode.removeChild(node);
18572             return;
18573             
18574         }
18575         
18576         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18577         
18578         // remove <a name=....> as rendering on yahoo mailer is borked with this.
18579         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18580         
18581         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18582         //    remove_keep_children = true;
18583         //}
18584         
18585         if (remove_keep_children) {
18586             this.cleanUpChildren(node);
18587             // inserts everything just before this node...
18588             while (node.childNodes.length) {
18589                 var cn = node.childNodes[0];
18590                 node.removeChild(cn);
18591                 node.parentNode.insertBefore(cn, node);
18592             }
18593             node.parentNode.removeChild(node);
18594             return;
18595         }
18596         
18597         if (!node.attributes || !node.attributes.length) {
18598             this.cleanUpChildren(node);
18599             return;
18600         }
18601         
18602         function cleanAttr(n,v)
18603         {
18604             
18605             if (v.match(/^\./) || v.match(/^\//)) {
18606                 return;
18607             }
18608             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18609                 return;
18610             }
18611             if (v.match(/^#/)) {
18612                 return;
18613             }
18614 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18615             node.removeAttribute(n);
18616             
18617         }
18618         
18619         var cwhite = this.cwhite;
18620         var cblack = this.cblack;
18621             
18622         function cleanStyle(n,v)
18623         {
18624             if (v.match(/expression/)) { //XSS?? should we even bother..
18625                 node.removeAttribute(n);
18626                 return;
18627             }
18628             
18629             var parts = v.split(/;/);
18630             var clean = [];
18631             
18632             Roo.each(parts, function(p) {
18633                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18634                 if (!p.length) {
18635                     return true;
18636                 }
18637                 var l = p.split(':').shift().replace(/\s+/g,'');
18638                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18639                 
18640                 if ( cwhite.length && cblack.indexOf(l) > -1) {
18641 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18642                     //node.removeAttribute(n);
18643                     return true;
18644                 }
18645                 //Roo.log()
18646                 // only allow 'c whitelisted system attributes'
18647                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
18648 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18649                     //node.removeAttribute(n);
18650                     return true;
18651                 }
18652                 
18653                 
18654                  
18655                 
18656                 clean.push(p);
18657                 return true;
18658             });
18659             if (clean.length) { 
18660                 node.setAttribute(n, clean.join(';'));
18661             } else {
18662                 node.removeAttribute(n);
18663             }
18664             
18665         }
18666         
18667         
18668         for (var i = node.attributes.length-1; i > -1 ; i--) {
18669             var a = node.attributes[i];
18670             //console.log(a);
18671             
18672             if (a.name.toLowerCase().substr(0,2)=='on')  {
18673                 node.removeAttribute(a.name);
18674                 continue;
18675             }
18676             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18677                 node.removeAttribute(a.name);
18678                 continue;
18679             }
18680             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18681                 cleanAttr(a.name,a.value); // fixme..
18682                 continue;
18683             }
18684             if (a.name == 'style') {
18685                 cleanStyle(a.name,a.value);
18686                 continue;
18687             }
18688             /// clean up MS crap..
18689             // tecnically this should be a list of valid class'es..
18690             
18691             
18692             if (a.name == 'class') {
18693                 if (a.value.match(/^Mso/)) {
18694                     node.className = '';
18695                 }
18696                 
18697                 if (a.value.match(/body/)) {
18698                     node.className = '';
18699                 }
18700                 continue;
18701             }
18702             
18703             // style cleanup!?
18704             // class cleanup?
18705             
18706         }
18707         
18708         
18709         this.cleanUpChildren(node);
18710         
18711         
18712     },
18713     /**
18714      * Clean up MS wordisms...
18715      */
18716     cleanWord : function(node)
18717     {
18718         var _t = this;
18719         var cleanWordChildren = function()
18720         {
18721             if (!node.childNodes.length) {
18722                 return;
18723             }
18724             for (var i = node.childNodes.length-1; i > -1 ; i--) {
18725                _t.cleanWord(node.childNodes[i]);
18726             }
18727         }
18728         
18729         
18730         if (!node) {
18731             this.cleanWord(this.doc.body);
18732             return;
18733         }
18734         if (node.nodeName == "#text") {
18735             // clean up silly Windows -- stuff?
18736             return; 
18737         }
18738         if (node.nodeName == "#comment") {
18739             node.parentNode.removeChild(node);
18740             // clean up silly Windows -- stuff?
18741             return; 
18742         }
18743         
18744         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18745             node.parentNode.removeChild(node);
18746             return;
18747         }
18748         
18749         // remove - but keep children..
18750         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18751             while (node.childNodes.length) {
18752                 var cn = node.childNodes[0];
18753                 node.removeChild(cn);
18754                 node.parentNode.insertBefore(cn, node);
18755             }
18756             node.parentNode.removeChild(node);
18757             cleanWordChildren();
18758             return;
18759         }
18760         // clean styles
18761         if (node.className.length) {
18762             
18763             var cn = node.className.split(/\W+/);
18764             var cna = [];
18765             Roo.each(cn, function(cls) {
18766                 if (cls.match(/Mso[a-zA-Z]+/)) {
18767                     return;
18768                 }
18769                 cna.push(cls);
18770             });
18771             node.className = cna.length ? cna.join(' ') : '';
18772             if (!cna.length) {
18773                 node.removeAttribute("class");
18774             }
18775         }
18776         
18777         if (node.hasAttribute("lang")) {
18778             node.removeAttribute("lang");
18779         }
18780         
18781         if (node.hasAttribute("style")) {
18782             
18783             var styles = node.getAttribute("style").split(";");
18784             var nstyle = [];
18785             Roo.each(styles, function(s) {
18786                 if (!s.match(/:/)) {
18787                     return;
18788                 }
18789                 var kv = s.split(":");
18790                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18791                     return;
18792                 }
18793                 // what ever is left... we allow.
18794                 nstyle.push(s);
18795             });
18796             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18797             if (!nstyle.length) {
18798                 node.removeAttribute('style');
18799             }
18800         }
18801         
18802         cleanWordChildren();
18803         
18804         
18805     },
18806     domToHTML : function(currentElement, depth, nopadtext) {
18807         
18808         depth = depth || 0;
18809         nopadtext = nopadtext || false;
18810     
18811         if (!currentElement) {
18812             return this.domToHTML(this.doc.body);
18813         }
18814         
18815         //Roo.log(currentElement);
18816         var j;
18817         var allText = false;
18818         var nodeName = currentElement.nodeName;
18819         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18820         
18821         if  (nodeName == '#text') {
18822             
18823             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18824         }
18825         
18826         
18827         var ret = '';
18828         if (nodeName != 'BODY') {
18829              
18830             var i = 0;
18831             // Prints the node tagName, such as <A>, <IMG>, etc
18832             if (tagName) {
18833                 var attr = [];
18834                 for(i = 0; i < currentElement.attributes.length;i++) {
18835                     // quoting?
18836                     var aname = currentElement.attributes.item(i).name;
18837                     if (!currentElement.attributes.item(i).value.length) {
18838                         continue;
18839                     }
18840                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18841                 }
18842                 
18843                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18844             } 
18845             else {
18846                 
18847                 // eack
18848             }
18849         } else {
18850             tagName = false;
18851         }
18852         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18853             return ret;
18854         }
18855         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18856             nopadtext = true;
18857         }
18858         
18859         
18860         // Traverse the tree
18861         i = 0;
18862         var currentElementChild = currentElement.childNodes.item(i);
18863         var allText = true;
18864         var innerHTML  = '';
18865         lastnode = '';
18866         while (currentElementChild) {
18867             // Formatting code (indent the tree so it looks nice on the screen)
18868             var nopad = nopadtext;
18869             if (lastnode == 'SPAN') {
18870                 nopad  = true;
18871             }
18872             // text
18873             if  (currentElementChild.nodeName == '#text') {
18874                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18875                 toadd = nopadtext ? toadd : toadd.trim();
18876                 if (!nopad && toadd.length > 80) {
18877                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
18878                 }
18879                 innerHTML  += toadd;
18880                 
18881                 i++;
18882                 currentElementChild = currentElement.childNodes.item(i);
18883                 lastNode = '';
18884                 continue;
18885             }
18886             allText = false;
18887             
18888             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
18889                 
18890             // Recursively traverse the tree structure of the child node
18891             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
18892             lastnode = currentElementChild.nodeName;
18893             i++;
18894             currentElementChild=currentElement.childNodes.item(i);
18895         }
18896         
18897         ret += innerHTML;
18898         
18899         if (!allText) {
18900                 // The remaining code is mostly for formatting the tree
18901             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
18902         }
18903         
18904         
18905         if (tagName) {
18906             ret+= "</"+tagName+">";
18907         }
18908         return ret;
18909         
18910     },
18911         
18912     applyBlacklists : function()
18913     {
18914         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
18915         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
18916         
18917         this.white = [];
18918         this.black = [];
18919         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18920             if (b.indexOf(tag) > -1) {
18921                 return;
18922             }
18923             this.white.push(tag);
18924             
18925         }, this);
18926         
18927         Roo.each(w, function(tag) {
18928             if (b.indexOf(tag) > -1) {
18929                 return;
18930             }
18931             if (this.white.indexOf(tag) > -1) {
18932                 return;
18933             }
18934             this.white.push(tag);
18935             
18936         }, this);
18937         
18938         
18939         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18940             if (w.indexOf(tag) > -1) {
18941                 return;
18942             }
18943             this.black.push(tag);
18944             
18945         }, this);
18946         
18947         Roo.each(b, function(tag) {
18948             if (w.indexOf(tag) > -1) {
18949                 return;
18950             }
18951             if (this.black.indexOf(tag) > -1) {
18952                 return;
18953             }
18954             this.black.push(tag);
18955             
18956         }, this);
18957         
18958         
18959         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
18960         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
18961         
18962         this.cwhite = [];
18963         this.cblack = [];
18964         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18965             if (b.indexOf(tag) > -1) {
18966                 return;
18967             }
18968             this.cwhite.push(tag);
18969             
18970         }, this);
18971         
18972         Roo.each(w, function(tag) {
18973             if (b.indexOf(tag) > -1) {
18974                 return;
18975             }
18976             if (this.cwhite.indexOf(tag) > -1) {
18977                 return;
18978             }
18979             this.cwhite.push(tag);
18980             
18981         }, this);
18982         
18983         
18984         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18985             if (w.indexOf(tag) > -1) {
18986                 return;
18987             }
18988             this.cblack.push(tag);
18989             
18990         }, this);
18991         
18992         Roo.each(b, function(tag) {
18993             if (w.indexOf(tag) > -1) {
18994                 return;
18995             }
18996             if (this.cblack.indexOf(tag) > -1) {
18997                 return;
18998             }
18999             this.cblack.push(tag);
19000             
19001         }, this);
19002     },
19003     
19004     setStylesheets : function(stylesheets)
19005     {
19006         if(typeof(stylesheets) == 'string'){
19007             Roo.get(this.iframe.contentDocument.head).createChild({
19008                 tag : 'link',
19009                 rel : 'stylesheet',
19010                 type : 'text/css',
19011                 href : stylesheets
19012             });
19013             
19014             return;
19015         }
19016         var _this = this;
19017      
19018         Roo.each(stylesheets, function(s) {
19019             if(!s.length){
19020                 return;
19021             }
19022             
19023             Roo.get(_this.iframe.contentDocument.head).createChild({
19024                 tag : 'link',
19025                 rel : 'stylesheet',
19026                 type : 'text/css',
19027                 href : s
19028             });
19029         });
19030
19031         
19032     },
19033     
19034     removeStylesheets : function()
19035     {
19036         var _this = this;
19037         
19038         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19039             s.remove();
19040         });
19041     }
19042     
19043     // hide stuff that is not compatible
19044     /**
19045      * @event blur
19046      * @hide
19047      */
19048     /**
19049      * @event change
19050      * @hide
19051      */
19052     /**
19053      * @event focus
19054      * @hide
19055      */
19056     /**
19057      * @event specialkey
19058      * @hide
19059      */
19060     /**
19061      * @cfg {String} fieldClass @hide
19062      */
19063     /**
19064      * @cfg {String} focusClass @hide
19065      */
19066     /**
19067      * @cfg {String} autoCreate @hide
19068      */
19069     /**
19070      * @cfg {String} inputType @hide
19071      */
19072     /**
19073      * @cfg {String} invalidClass @hide
19074      */
19075     /**
19076      * @cfg {String} invalidText @hide
19077      */
19078     /**
19079      * @cfg {String} msgFx @hide
19080      */
19081     /**
19082      * @cfg {String} validateOnBlur @hide
19083      */
19084 });
19085
19086 Roo.HtmlEditorCore.white = [
19087         'area', 'br', 'img', 'input', 'hr', 'wbr',
19088         
19089        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
19090        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
19091        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
19092        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
19093        'table',   'ul',         'xmp', 
19094        
19095        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
19096       'thead',   'tr', 
19097      
19098       'dir', 'menu', 'ol', 'ul', 'dl',
19099        
19100       'embed',  'object'
19101 ];
19102
19103
19104 Roo.HtmlEditorCore.black = [
19105     //    'embed',  'object', // enable - backend responsiblity to clean thiese
19106         'applet', // 
19107         'base',   'basefont', 'bgsound', 'blink',  'body', 
19108         'frame',  'frameset', 'head',    'html',   'ilayer', 
19109         'iframe', 'layer',  'link',     'meta',    'object',   
19110         'script', 'style' ,'title',  'xml' // clean later..
19111 ];
19112 Roo.HtmlEditorCore.clean = [
19113     'script', 'style', 'title', 'xml'
19114 ];
19115 Roo.HtmlEditorCore.remove = [
19116     'font'
19117 ];
19118 // attributes..
19119
19120 Roo.HtmlEditorCore.ablack = [
19121     'on'
19122 ];
19123     
19124 Roo.HtmlEditorCore.aclean = [ 
19125     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
19126 ];
19127
19128 // protocols..
19129 Roo.HtmlEditorCore.pwhite= [
19130         'http',  'https',  'mailto'
19131 ];
19132
19133 // white listed style attributes.
19134 Roo.HtmlEditorCore.cwhite= [
19135       //  'text-align', /// default is to allow most things..
19136       
19137          
19138 //        'font-size'//??
19139 ];
19140
19141 // black listed style attributes.
19142 Roo.HtmlEditorCore.cblack= [
19143       //  'font-size' -- this can be set by the project 
19144 ];
19145
19146
19147 Roo.HtmlEditorCore.swapCodes   =[ 
19148     [    8211, "--" ], 
19149     [    8212, "--" ], 
19150     [    8216,  "'" ],  
19151     [    8217, "'" ],  
19152     [    8220, '"' ],  
19153     [    8221, '"' ],  
19154     [    8226, "*" ],  
19155     [    8230, "..." ]
19156 ]; 
19157
19158     /*
19159  * - LGPL
19160  *
19161  * HtmlEditor
19162  * 
19163  */
19164
19165 /**
19166  * @class Roo.bootstrap.HtmlEditor
19167  * @extends Roo.bootstrap.TextArea
19168  * Bootstrap HtmlEditor class
19169
19170  * @constructor
19171  * Create a new HtmlEditor
19172  * @param {Object} config The config object
19173  */
19174
19175 Roo.bootstrap.HtmlEditor = function(config){
19176     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19177     if (!this.toolbars) {
19178         this.toolbars = [];
19179     }
19180     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19181     this.addEvents({
19182             /**
19183              * @event initialize
19184              * Fires when the editor is fully initialized (including the iframe)
19185              * @param {HtmlEditor} this
19186              */
19187             initialize: true,
19188             /**
19189              * @event activate
19190              * Fires when the editor is first receives the focus. Any insertion must wait
19191              * until after this event.
19192              * @param {HtmlEditor} this
19193              */
19194             activate: true,
19195              /**
19196              * @event beforesync
19197              * Fires before the textarea is updated with content from the editor iframe. Return false
19198              * to cancel the sync.
19199              * @param {HtmlEditor} this
19200              * @param {String} html
19201              */
19202             beforesync: true,
19203              /**
19204              * @event beforepush
19205              * Fires before the iframe editor is updated with content from the textarea. Return false
19206              * to cancel the push.
19207              * @param {HtmlEditor} this
19208              * @param {String} html
19209              */
19210             beforepush: true,
19211              /**
19212              * @event sync
19213              * Fires when the textarea is updated with content from the editor iframe.
19214              * @param {HtmlEditor} this
19215              * @param {String} html
19216              */
19217             sync: true,
19218              /**
19219              * @event push
19220              * Fires when the iframe editor is updated with content from the textarea.
19221              * @param {HtmlEditor} this
19222              * @param {String} html
19223              */
19224             push: true,
19225              /**
19226              * @event editmodechange
19227              * Fires when the editor switches edit modes
19228              * @param {HtmlEditor} this
19229              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19230              */
19231             editmodechange: true,
19232             /**
19233              * @event editorevent
19234              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19235              * @param {HtmlEditor} this
19236              */
19237             editorevent: true,
19238             /**
19239              * @event firstfocus
19240              * Fires when on first focus - needed by toolbars..
19241              * @param {HtmlEditor} this
19242              */
19243             firstfocus: true,
19244             /**
19245              * @event autosave
19246              * Auto save the htmlEditor value as a file into Events
19247              * @param {HtmlEditor} this
19248              */
19249             autosave: true,
19250             /**
19251              * @event savedpreview
19252              * preview the saved version of htmlEditor
19253              * @param {HtmlEditor} this
19254              */
19255             savedpreview: true
19256         });
19257 };
19258
19259
19260 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
19261     
19262     
19263       /**
19264      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19265      */
19266     toolbars : false,
19267    
19268      /**
19269      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
19270      *                        Roo.resizable.
19271      */
19272     resizable : false,
19273      /**
19274      * @cfg {Number} height (in pixels)
19275      */   
19276     height: 300,
19277    /**
19278      * @cfg {Number} width (in pixels)
19279      */   
19280     width: false,
19281     
19282     /**
19283      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19284      * 
19285      */
19286     stylesheets: false,
19287     
19288     // id of frame..
19289     frameId: false,
19290     
19291     // private properties
19292     validationEvent : false,
19293     deferHeight: true,
19294     initialized : false,
19295     activated : false,
19296     
19297     onFocus : Roo.emptyFn,
19298     iframePad:3,
19299     hideMode:'offsets',
19300     
19301     
19302     tbContainer : false,
19303     
19304     toolbarContainer :function() {
19305         return this.wrap.select('.x-html-editor-tb',true).first();
19306     },
19307
19308     /**
19309      * Protected method that will not generally be called directly. It
19310      * is called when the editor creates its toolbar. Override this method if you need to
19311      * add custom toolbar buttons.
19312      * @param {HtmlEditor} editor
19313      */
19314     createToolbar : function(){
19315         
19316         Roo.log("create toolbars");
19317         
19318         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19319         this.toolbars[0].render(this.toolbarContainer());
19320         
19321         return;
19322         
19323 //        if (!editor.toolbars || !editor.toolbars.length) {
19324 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19325 //        }
19326 //        
19327 //        for (var i =0 ; i < editor.toolbars.length;i++) {
19328 //            editor.toolbars[i] = Roo.factory(
19329 //                    typeof(editor.toolbars[i]) == 'string' ?
19330 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
19331 //                Roo.bootstrap.HtmlEditor);
19332 //            editor.toolbars[i].init(editor);
19333 //        }
19334     },
19335
19336      
19337     // private
19338     onRender : function(ct, position)
19339     {
19340        // Roo.log("Call onRender: " + this.xtype);
19341         var _t = this;
19342         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19343       
19344         this.wrap = this.inputEl().wrap({
19345             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19346         });
19347         
19348         this.editorcore.onRender(ct, position);
19349          
19350         if (this.resizable) {
19351             this.resizeEl = new Roo.Resizable(this.wrap, {
19352                 pinned : true,
19353                 wrap: true,
19354                 dynamic : true,
19355                 minHeight : this.height,
19356                 height: this.height,
19357                 handles : this.resizable,
19358                 width: this.width,
19359                 listeners : {
19360                     resize : function(r, w, h) {
19361                         _t.onResize(w,h); // -something
19362                     }
19363                 }
19364             });
19365             
19366         }
19367         this.createToolbar(this);
19368        
19369         
19370         if(!this.width && this.resizable){
19371             this.setSize(this.wrap.getSize());
19372         }
19373         if (this.resizeEl) {
19374             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19375             // should trigger onReize..
19376         }
19377         
19378     },
19379
19380     // private
19381     onResize : function(w, h)
19382     {
19383         Roo.log('resize: ' +w + ',' + h );
19384         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19385         var ew = false;
19386         var eh = false;
19387         
19388         if(this.inputEl() ){
19389             if(typeof w == 'number'){
19390                 var aw = w - this.wrap.getFrameWidth('lr');
19391                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19392                 ew = aw;
19393             }
19394             if(typeof h == 'number'){
19395                  var tbh = -11;  // fixme it needs to tool bar size!
19396                 for (var i =0; i < this.toolbars.length;i++) {
19397                     // fixme - ask toolbars for heights?
19398                     tbh += this.toolbars[i].el.getHeight();
19399                     //if (this.toolbars[i].footer) {
19400                     //    tbh += this.toolbars[i].footer.el.getHeight();
19401                     //}
19402                 }
19403               
19404                 
19405                 
19406                 
19407                 
19408                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19409                 ah -= 5; // knock a few pixes off for look..
19410                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19411                 var eh = ah;
19412             }
19413         }
19414         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19415         this.editorcore.onResize(ew,eh);
19416         
19417     },
19418
19419     /**
19420      * Toggles the editor between standard and source edit mode.
19421      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19422      */
19423     toggleSourceEdit : function(sourceEditMode)
19424     {
19425         this.editorcore.toggleSourceEdit(sourceEditMode);
19426         
19427         if(this.editorcore.sourceEditMode){
19428             Roo.log('editor - showing textarea');
19429             
19430 //            Roo.log('in');
19431 //            Roo.log(this.syncValue());
19432             this.syncValue();
19433             this.inputEl().removeClass(['hide', 'x-hidden']);
19434             this.inputEl().dom.removeAttribute('tabIndex');
19435             this.inputEl().focus();
19436         }else{
19437             Roo.log('editor - hiding textarea');
19438 //            Roo.log('out')
19439 //            Roo.log(this.pushValue()); 
19440             this.pushValue();
19441             
19442             this.inputEl().addClass(['hide', 'x-hidden']);
19443             this.inputEl().dom.setAttribute('tabIndex', -1);
19444             //this.deferFocus();
19445         }
19446          
19447         if(this.resizable){
19448             this.setSize(this.wrap.getSize());
19449         }
19450         
19451         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19452     },
19453  
19454     // private (for BoxComponent)
19455     adjustSize : Roo.BoxComponent.prototype.adjustSize,
19456
19457     // private (for BoxComponent)
19458     getResizeEl : function(){
19459         return this.wrap;
19460     },
19461
19462     // private (for BoxComponent)
19463     getPositionEl : function(){
19464         return this.wrap;
19465     },
19466
19467     // private
19468     initEvents : function(){
19469         this.originalValue = this.getValue();
19470     },
19471
19472 //    /**
19473 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19474 //     * @method
19475 //     */
19476 //    markInvalid : Roo.emptyFn,
19477 //    /**
19478 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19479 //     * @method
19480 //     */
19481 //    clearInvalid : Roo.emptyFn,
19482
19483     setValue : function(v){
19484         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19485         this.editorcore.pushValue();
19486     },
19487
19488      
19489     // private
19490     deferFocus : function(){
19491         this.focus.defer(10, this);
19492     },
19493
19494     // doc'ed in Field
19495     focus : function(){
19496         this.editorcore.focus();
19497         
19498     },
19499       
19500
19501     // private
19502     onDestroy : function(){
19503         
19504         
19505         
19506         if(this.rendered){
19507             
19508             for (var i =0; i < this.toolbars.length;i++) {
19509                 // fixme - ask toolbars for heights?
19510                 this.toolbars[i].onDestroy();
19511             }
19512             
19513             this.wrap.dom.innerHTML = '';
19514             this.wrap.remove();
19515         }
19516     },
19517
19518     // private
19519     onFirstFocus : function(){
19520         //Roo.log("onFirstFocus");
19521         this.editorcore.onFirstFocus();
19522          for (var i =0; i < this.toolbars.length;i++) {
19523             this.toolbars[i].onFirstFocus();
19524         }
19525         
19526     },
19527     
19528     // private
19529     syncValue : function()
19530     {   
19531         this.editorcore.syncValue();
19532     },
19533     
19534     pushValue : function()
19535     {   
19536         this.editorcore.pushValue();
19537     }
19538      
19539     
19540     // hide stuff that is not compatible
19541     /**
19542      * @event blur
19543      * @hide
19544      */
19545     /**
19546      * @event change
19547      * @hide
19548      */
19549     /**
19550      * @event focus
19551      * @hide
19552      */
19553     /**
19554      * @event specialkey
19555      * @hide
19556      */
19557     /**
19558      * @cfg {String} fieldClass @hide
19559      */
19560     /**
19561      * @cfg {String} focusClass @hide
19562      */
19563     /**
19564      * @cfg {String} autoCreate @hide
19565      */
19566     /**
19567      * @cfg {String} inputType @hide
19568      */
19569     /**
19570      * @cfg {String} invalidClass @hide
19571      */
19572     /**
19573      * @cfg {String} invalidText @hide
19574      */
19575     /**
19576      * @cfg {String} msgFx @hide
19577      */
19578     /**
19579      * @cfg {String} validateOnBlur @hide
19580      */
19581 });
19582  
19583     
19584    
19585    
19586    
19587       
19588 Roo.namespace('Roo.bootstrap.htmleditor');
19589 /**
19590  * @class Roo.bootstrap.HtmlEditorToolbar1
19591  * Basic Toolbar
19592  * 
19593  * Usage:
19594  *
19595  new Roo.bootstrap.HtmlEditor({
19596     ....
19597     toolbars : [
19598         new Roo.bootstrap.HtmlEditorToolbar1({
19599             disable : { fonts: 1 , format: 1, ..., ... , ...],
19600             btns : [ .... ]
19601         })
19602     }
19603      
19604  * 
19605  * @cfg {Object} disable List of elements to disable..
19606  * @cfg {Array} btns List of additional buttons.
19607  * 
19608  * 
19609  * NEEDS Extra CSS? 
19610  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19611  */
19612  
19613 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19614 {
19615     
19616     Roo.apply(this, config);
19617     
19618     // default disabled, based on 'good practice'..
19619     this.disable = this.disable || {};
19620     Roo.applyIf(this.disable, {
19621         fontSize : true,
19622         colors : true,
19623         specialElements : true
19624     });
19625     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19626     
19627     this.editor = config.editor;
19628     this.editorcore = config.editor.editorcore;
19629     
19630     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19631     
19632     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19633     // dont call parent... till later.
19634 }
19635 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
19636      
19637     bar : true,
19638     
19639     editor : false,
19640     editorcore : false,
19641     
19642     
19643     formats : [
19644         "p" ,  
19645         "h1","h2","h3","h4","h5","h6", 
19646         "pre", "code", 
19647         "abbr", "acronym", "address", "cite", "samp", "var",
19648         'div','span'
19649     ],
19650     
19651     onRender : function(ct, position)
19652     {
19653        // Roo.log("Call onRender: " + this.xtype);
19654         
19655        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19656        Roo.log(this.el);
19657        this.el.dom.style.marginBottom = '0';
19658        var _this = this;
19659        var editorcore = this.editorcore;
19660        var editor= this.editor;
19661        
19662        var children = [];
19663        var btn = function(id,cmd , toggle, handler){
19664        
19665             var  event = toggle ? 'toggle' : 'click';
19666        
19667             var a = {
19668                 size : 'sm',
19669                 xtype: 'Button',
19670                 xns: Roo.bootstrap,
19671                 glyphicon : id,
19672                 cmd : id || cmd,
19673                 enableToggle:toggle !== false,
19674                 //html : 'submit'
19675                 pressed : toggle ? false : null,
19676                 listeners : {}
19677             }
19678             a.listeners[toggle ? 'toggle' : 'click'] = function() {
19679                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
19680             }
19681             children.push(a);
19682             return a;
19683        }
19684         
19685         var style = {
19686                 xtype: 'Button',
19687                 size : 'sm',
19688                 xns: Roo.bootstrap,
19689                 glyphicon : 'font',
19690                 //html : 'submit'
19691                 menu : {
19692                     xtype: 'Menu',
19693                     xns: Roo.bootstrap,
19694                     items:  []
19695                 }
19696         };
19697         Roo.each(this.formats, function(f) {
19698             style.menu.items.push({
19699                 xtype :'MenuItem',
19700                 xns: Roo.bootstrap,
19701                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19702                 tagname : f,
19703                 listeners : {
19704                     click : function()
19705                     {
19706                         editorcore.insertTag(this.tagname);
19707                         editor.focus();
19708                     }
19709                 }
19710                 
19711             });
19712         });
19713          children.push(style);   
19714             
19715             
19716         btn('bold',false,true);
19717         btn('italic',false,true);
19718         btn('align-left', 'justifyleft',true);
19719         btn('align-center', 'justifycenter',true);
19720         btn('align-right' , 'justifyright',true);
19721         btn('link', false, false, function(btn) {
19722             //Roo.log("create link?");
19723             var url = prompt(this.createLinkText, this.defaultLinkValue);
19724             if(url && url != 'http:/'+'/'){
19725                 this.editorcore.relayCmd('createlink', url);
19726             }
19727         }),
19728         btn('list','insertunorderedlist',true);
19729         btn('pencil', false,true, function(btn){
19730                 Roo.log(this);
19731                 
19732                 this.toggleSourceEdit(btn.pressed);
19733         });
19734         /*
19735         var cog = {
19736                 xtype: 'Button',
19737                 size : 'sm',
19738                 xns: Roo.bootstrap,
19739                 glyphicon : 'cog',
19740                 //html : 'submit'
19741                 menu : {
19742                     xtype: 'Menu',
19743                     xns: Roo.bootstrap,
19744                     items:  []
19745                 }
19746         };
19747         
19748         cog.menu.items.push({
19749             xtype :'MenuItem',
19750             xns: Roo.bootstrap,
19751             html : Clean styles,
19752             tagname : f,
19753             listeners : {
19754                 click : function()
19755                 {
19756                     editorcore.insertTag(this.tagname);
19757                     editor.focus();
19758                 }
19759             }
19760             
19761         });
19762        */
19763         
19764          
19765        this.xtype = 'NavSimplebar';
19766         
19767         for(var i=0;i< children.length;i++) {
19768             
19769             this.buttons.add(this.addxtypeChild(children[i]));
19770             
19771         }
19772         
19773         editor.on('editorevent', this.updateToolbar, this);
19774     },
19775     onBtnClick : function(id)
19776     {
19777        this.editorcore.relayCmd(id);
19778        this.editorcore.focus();
19779     },
19780     
19781     /**
19782      * Protected method that will not generally be called directly. It triggers
19783      * a toolbar update by reading the markup state of the current selection in the editor.
19784      */
19785     updateToolbar: function(){
19786
19787         if(!this.editorcore.activated){
19788             this.editor.onFirstFocus(); // is this neeed?
19789             return;
19790         }
19791
19792         var btns = this.buttons; 
19793         var doc = this.editorcore.doc;
19794         btns.get('bold').setActive(doc.queryCommandState('bold'));
19795         btns.get('italic').setActive(doc.queryCommandState('italic'));
19796         //btns.get('underline').setActive(doc.queryCommandState('underline'));
19797         
19798         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19799         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19800         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19801         
19802         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19803         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19804          /*
19805         
19806         var ans = this.editorcore.getAllAncestors();
19807         if (this.formatCombo) {
19808             
19809             
19810             var store = this.formatCombo.store;
19811             this.formatCombo.setValue("");
19812             for (var i =0; i < ans.length;i++) {
19813                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19814                     // select it..
19815                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19816                     break;
19817                 }
19818             }
19819         }
19820         
19821         
19822         
19823         // hides menus... - so this cant be on a menu...
19824         Roo.bootstrap.MenuMgr.hideAll();
19825         */
19826         Roo.bootstrap.MenuMgr.hideAll();
19827         //this.editorsyncValue();
19828     },
19829     onFirstFocus: function() {
19830         this.buttons.each(function(item){
19831            item.enable();
19832         });
19833     },
19834     toggleSourceEdit : function(sourceEditMode){
19835         
19836           
19837         if(sourceEditMode){
19838             Roo.log("disabling buttons");
19839            this.buttons.each( function(item){
19840                 if(item.cmd != 'pencil'){
19841                     item.disable();
19842                 }
19843             });
19844           
19845         }else{
19846             Roo.log("enabling buttons");
19847             if(this.editorcore.initialized){
19848                 this.buttons.each( function(item){
19849                     item.enable();
19850                 });
19851             }
19852             
19853         }
19854         Roo.log("calling toggole on editor");
19855         // tell the editor that it's been pressed..
19856         this.editor.toggleSourceEdit(sourceEditMode);
19857        
19858     }
19859 });
19860
19861
19862
19863
19864
19865 /**
19866  * @class Roo.bootstrap.Table.AbstractSelectionModel
19867  * @extends Roo.util.Observable
19868  * Abstract base class for grid SelectionModels.  It provides the interface that should be
19869  * implemented by descendant classes.  This class should not be directly instantiated.
19870  * @constructor
19871  */
19872 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19873     this.locked = false;
19874     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19875 };
19876
19877
19878 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
19879     /** @ignore Called by the grid automatically. Do not call directly. */
19880     init : function(grid){
19881         this.grid = grid;
19882         this.initEvents();
19883     },
19884
19885     /**
19886      * Locks the selections.
19887      */
19888     lock : function(){
19889         this.locked = true;
19890     },
19891
19892     /**
19893      * Unlocks the selections.
19894      */
19895     unlock : function(){
19896         this.locked = false;
19897     },
19898
19899     /**
19900      * Returns true if the selections are locked.
19901      * @return {Boolean}
19902      */
19903     isLocked : function(){
19904         return this.locked;
19905     }
19906 });
19907 /**
19908  * @extends Roo.bootstrap.Table.AbstractSelectionModel
19909  * @class Roo.bootstrap.Table.RowSelectionModel
19910  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19911  * It supports multiple selections and keyboard selection/navigation. 
19912  * @constructor
19913  * @param {Object} config
19914  */
19915
19916 Roo.bootstrap.Table.RowSelectionModel = function(config){
19917     Roo.apply(this, config);
19918     this.selections = new Roo.util.MixedCollection(false, function(o){
19919         return o.id;
19920     });
19921
19922     this.last = false;
19923     this.lastActive = false;
19924
19925     this.addEvents({
19926         /**
19927              * @event selectionchange
19928              * Fires when the selection changes
19929              * @param {SelectionModel} this
19930              */
19931             "selectionchange" : true,
19932         /**
19933              * @event afterselectionchange
19934              * Fires after the selection changes (eg. by key press or clicking)
19935              * @param {SelectionModel} this
19936              */
19937             "afterselectionchange" : true,
19938         /**
19939              * @event beforerowselect
19940              * Fires when a row is selected being selected, return false to cancel.
19941              * @param {SelectionModel} this
19942              * @param {Number} rowIndex The selected index
19943              * @param {Boolean} keepExisting False if other selections will be cleared
19944              */
19945             "beforerowselect" : true,
19946         /**
19947              * @event rowselect
19948              * Fires when a row is selected.
19949              * @param {SelectionModel} this
19950              * @param {Number} rowIndex The selected index
19951              * @param {Roo.data.Record} r The record
19952              */
19953             "rowselect" : true,
19954         /**
19955              * @event rowdeselect
19956              * Fires when a row is deselected.
19957              * @param {SelectionModel} this
19958              * @param {Number} rowIndex The selected index
19959              */
19960         "rowdeselect" : true
19961     });
19962     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19963     this.locked = false;
19964 };
19965
19966 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
19967     /**
19968      * @cfg {Boolean} singleSelect
19969      * True to allow selection of only one row at a time (defaults to false)
19970      */
19971     singleSelect : false,
19972
19973     // private
19974     initEvents : function(){
19975
19976         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19977             this.grid.on("mousedown", this.handleMouseDown, this);
19978         }else{ // allow click to work like normal
19979             this.grid.on("rowclick", this.handleDragableRowClick, this);
19980         }
19981
19982         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19983             "up" : function(e){
19984                 if(!e.shiftKey){
19985                     this.selectPrevious(e.shiftKey);
19986                 }else if(this.last !== false && this.lastActive !== false){
19987                     var last = this.last;
19988                     this.selectRange(this.last,  this.lastActive-1);
19989                     this.grid.getView().focusRow(this.lastActive);
19990                     if(last !== false){
19991                         this.last = last;
19992                     }
19993                 }else{
19994                     this.selectFirstRow();
19995                 }
19996                 this.fireEvent("afterselectionchange", this);
19997             },
19998             "down" : function(e){
19999                 if(!e.shiftKey){
20000                     this.selectNext(e.shiftKey);
20001                 }else if(this.last !== false && this.lastActive !== false){
20002                     var last = this.last;
20003                     this.selectRange(this.last,  this.lastActive+1);
20004                     this.grid.getView().focusRow(this.lastActive);
20005                     if(last !== false){
20006                         this.last = last;
20007                     }
20008                 }else{
20009                     this.selectFirstRow();
20010                 }
20011                 this.fireEvent("afterselectionchange", this);
20012             },
20013             scope: this
20014         });
20015
20016         var view = this.grid.view;
20017         view.on("refresh", this.onRefresh, this);
20018         view.on("rowupdated", this.onRowUpdated, this);
20019         view.on("rowremoved", this.onRemove, this);
20020     },
20021
20022     // private
20023     onRefresh : function(){
20024         var ds = this.grid.dataSource, i, v = this.grid.view;
20025         var s = this.selections;
20026         s.each(function(r){
20027             if((i = ds.indexOfId(r.id)) != -1){
20028                 v.onRowSelect(i);
20029             }else{
20030                 s.remove(r);
20031             }
20032         });
20033     },
20034
20035     // private
20036     onRemove : function(v, index, r){
20037         this.selections.remove(r);
20038     },
20039
20040     // private
20041     onRowUpdated : function(v, index, r){
20042         if(this.isSelected(r)){
20043             v.onRowSelect(index);
20044         }
20045     },
20046
20047     /**
20048      * Select records.
20049      * @param {Array} records The records to select
20050      * @param {Boolean} keepExisting (optional) True to keep existing selections
20051      */
20052     selectRecords : function(records, keepExisting){
20053         if(!keepExisting){
20054             this.clearSelections();
20055         }
20056         var ds = this.grid.dataSource;
20057         for(var i = 0, len = records.length; i < len; i++){
20058             this.selectRow(ds.indexOf(records[i]), true);
20059         }
20060     },
20061
20062     /**
20063      * Gets the number of selected rows.
20064      * @return {Number}
20065      */
20066     getCount : function(){
20067         return this.selections.length;
20068     },
20069
20070     /**
20071      * Selects the first row in the grid.
20072      */
20073     selectFirstRow : function(){
20074         this.selectRow(0);
20075     },
20076
20077     /**
20078      * Select the last row.
20079      * @param {Boolean} keepExisting (optional) True to keep existing selections
20080      */
20081     selectLastRow : function(keepExisting){
20082         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20083     },
20084
20085     /**
20086      * Selects the row immediately following the last selected row.
20087      * @param {Boolean} keepExisting (optional) True to keep existing selections
20088      */
20089     selectNext : function(keepExisting){
20090         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20091             this.selectRow(this.last+1, keepExisting);
20092             this.grid.getView().focusRow(this.last);
20093         }
20094     },
20095
20096     /**
20097      * Selects the row that precedes the last selected row.
20098      * @param {Boolean} keepExisting (optional) True to keep existing selections
20099      */
20100     selectPrevious : function(keepExisting){
20101         if(this.last){
20102             this.selectRow(this.last-1, keepExisting);
20103             this.grid.getView().focusRow(this.last);
20104         }
20105     },
20106
20107     /**
20108      * Returns the selected records
20109      * @return {Array} Array of selected records
20110      */
20111     getSelections : function(){
20112         return [].concat(this.selections.items);
20113     },
20114
20115     /**
20116      * Returns the first selected record.
20117      * @return {Record}
20118      */
20119     getSelected : function(){
20120         return this.selections.itemAt(0);
20121     },
20122
20123
20124     /**
20125      * Clears all selections.
20126      */
20127     clearSelections : function(fast){
20128         if(this.locked) return;
20129         if(fast !== true){
20130             var ds = this.grid.dataSource;
20131             var s = this.selections;
20132             s.each(function(r){
20133                 this.deselectRow(ds.indexOfId(r.id));
20134             }, this);
20135             s.clear();
20136         }else{
20137             this.selections.clear();
20138         }
20139         this.last = false;
20140     },
20141
20142
20143     /**
20144      * Selects all rows.
20145      */
20146     selectAll : function(){
20147         if(this.locked) return;
20148         this.selections.clear();
20149         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20150             this.selectRow(i, true);
20151         }
20152     },
20153
20154     /**
20155      * Returns True if there is a selection.
20156      * @return {Boolean}
20157      */
20158     hasSelection : function(){
20159         return this.selections.length > 0;
20160     },
20161
20162     /**
20163      * Returns True if the specified row is selected.
20164      * @param {Number/Record} record The record or index of the record to check
20165      * @return {Boolean}
20166      */
20167     isSelected : function(index){
20168         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20169         return (r && this.selections.key(r.id) ? true : false);
20170     },
20171
20172     /**
20173      * Returns True if the specified record id is selected.
20174      * @param {String} id The id of record to check
20175      * @return {Boolean}
20176      */
20177     isIdSelected : function(id){
20178         return (this.selections.key(id) ? true : false);
20179     },
20180
20181     // private
20182     handleMouseDown : function(e, t){
20183         var view = this.grid.getView(), rowIndex;
20184         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20185             return;
20186         };
20187         if(e.shiftKey && this.last !== false){
20188             var last = this.last;
20189             this.selectRange(last, rowIndex, e.ctrlKey);
20190             this.last = last; // reset the last
20191             view.focusRow(rowIndex);
20192         }else{
20193             var isSelected = this.isSelected(rowIndex);
20194             if(e.button !== 0 && isSelected){
20195                 view.focusRow(rowIndex);
20196             }else if(e.ctrlKey && isSelected){
20197                 this.deselectRow(rowIndex);
20198             }else if(!isSelected){
20199                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20200                 view.focusRow(rowIndex);
20201             }
20202         }
20203         this.fireEvent("afterselectionchange", this);
20204     },
20205     // private
20206     handleDragableRowClick :  function(grid, rowIndex, e) 
20207     {
20208         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20209             this.selectRow(rowIndex, false);
20210             grid.view.focusRow(rowIndex);
20211              this.fireEvent("afterselectionchange", this);
20212         }
20213     },
20214     
20215     /**
20216      * Selects multiple rows.
20217      * @param {Array} rows Array of the indexes of the row to select
20218      * @param {Boolean} keepExisting (optional) True to keep existing selections
20219      */
20220     selectRows : function(rows, keepExisting){
20221         if(!keepExisting){
20222             this.clearSelections();
20223         }
20224         for(var i = 0, len = rows.length; i < len; i++){
20225             this.selectRow(rows[i], true);
20226         }
20227     },
20228
20229     /**
20230      * Selects a range of rows. All rows in between startRow and endRow are also selected.
20231      * @param {Number} startRow The index of the first row in the range
20232      * @param {Number} endRow The index of the last row in the range
20233      * @param {Boolean} keepExisting (optional) True to retain existing selections
20234      */
20235     selectRange : function(startRow, endRow, keepExisting){
20236         if(this.locked) return;
20237         if(!keepExisting){
20238             this.clearSelections();
20239         }
20240         if(startRow <= endRow){
20241             for(var i = startRow; i <= endRow; i++){
20242                 this.selectRow(i, true);
20243             }
20244         }else{
20245             for(var i = startRow; i >= endRow; i--){
20246                 this.selectRow(i, true);
20247             }
20248         }
20249     },
20250
20251     /**
20252      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20253      * @param {Number} startRow The index of the first row in the range
20254      * @param {Number} endRow The index of the last row in the range
20255      */
20256     deselectRange : function(startRow, endRow, preventViewNotify){
20257         if(this.locked) return;
20258         for(var i = startRow; i <= endRow; i++){
20259             this.deselectRow(i, preventViewNotify);
20260         }
20261     },
20262
20263     /**
20264      * Selects a row.
20265      * @param {Number} row The index of the row to select
20266      * @param {Boolean} keepExisting (optional) True to keep existing selections
20267      */
20268     selectRow : function(index, keepExisting, preventViewNotify){
20269         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20270         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20271             if(!keepExisting || this.singleSelect){
20272                 this.clearSelections();
20273             }
20274             var r = this.grid.dataSource.getAt(index);
20275             this.selections.add(r);
20276             this.last = this.lastActive = index;
20277             if(!preventViewNotify){
20278                 this.grid.getView().onRowSelect(index);
20279             }
20280             this.fireEvent("rowselect", this, index, r);
20281             this.fireEvent("selectionchange", this);
20282         }
20283     },
20284
20285     /**
20286      * Deselects a row.
20287      * @param {Number} row The index of the row to deselect
20288      */
20289     deselectRow : function(index, preventViewNotify){
20290         if(this.locked) return;
20291         if(this.last == index){
20292             this.last = false;
20293         }
20294         if(this.lastActive == index){
20295             this.lastActive = false;
20296         }
20297         var r = this.grid.dataSource.getAt(index);
20298         this.selections.remove(r);
20299         if(!preventViewNotify){
20300             this.grid.getView().onRowDeselect(index);
20301         }
20302         this.fireEvent("rowdeselect", this, index);
20303         this.fireEvent("selectionchange", this);
20304     },
20305
20306     // private
20307     restoreLast : function(){
20308         if(this._last){
20309             this.last = this._last;
20310         }
20311     },
20312
20313     // private
20314     acceptsNav : function(row, col, cm){
20315         return !cm.isHidden(col) && cm.isCellEditable(col, row);
20316     },
20317
20318     // private
20319     onEditorKey : function(field, e){
20320         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20321         if(k == e.TAB){
20322             e.stopEvent();
20323             ed.completeEdit();
20324             if(e.shiftKey){
20325                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20326             }else{
20327                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20328             }
20329         }else if(k == e.ENTER && !e.ctrlKey){
20330             e.stopEvent();
20331             ed.completeEdit();
20332             if(e.shiftKey){
20333                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20334             }else{
20335                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20336             }
20337         }else if(k == e.ESC){
20338             ed.cancelEdit();
20339         }
20340         if(newCell){
20341             g.startEditing(newCell[0], newCell[1]);
20342         }
20343     }
20344 });/*
20345  * Based on:
20346  * Ext JS Library 1.1.1
20347  * Copyright(c) 2006-2007, Ext JS, LLC.
20348  *
20349  * Originally Released Under LGPL - original licence link has changed is not relivant.
20350  *
20351  * Fork - LGPL
20352  * <script type="text/javascript">
20353  */
20354  
20355 /**
20356  * @class Roo.bootstrap.PagingToolbar
20357  * @extends Roo.Row
20358  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20359  * @constructor
20360  * Create a new PagingToolbar
20361  * @param {Object} config The config object
20362  */
20363 Roo.bootstrap.PagingToolbar = function(config)
20364 {
20365     // old args format still supported... - xtype is prefered..
20366         // created from xtype...
20367     var ds = config.dataSource;
20368     this.toolbarItems = [];
20369     if (config.items) {
20370         this.toolbarItems = config.items;
20371 //        config.items = [];
20372     }
20373     
20374     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20375     this.ds = ds;
20376     this.cursor = 0;
20377     if (ds) { 
20378         this.bind(ds);
20379     }
20380     
20381     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20382     
20383 };
20384
20385 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20386     /**
20387      * @cfg {Roo.data.Store} dataSource
20388      * The underlying data store providing the paged data
20389      */
20390     /**
20391      * @cfg {String/HTMLElement/Element} container
20392      * container The id or element that will contain the toolbar
20393      */
20394     /**
20395      * @cfg {Boolean} displayInfo
20396      * True to display the displayMsg (defaults to false)
20397      */
20398     /**
20399      * @cfg {Number} pageSize
20400      * The number of records to display per page (defaults to 20)
20401      */
20402     pageSize: 20,
20403     /**
20404      * @cfg {String} displayMsg
20405      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20406      */
20407     displayMsg : 'Displaying {0} - {1} of {2}',
20408     /**
20409      * @cfg {String} emptyMsg
20410      * The message to display when no records are found (defaults to "No data to display")
20411      */
20412     emptyMsg : 'No data to display',
20413     /**
20414      * Customizable piece of the default paging text (defaults to "Page")
20415      * @type String
20416      */
20417     beforePageText : "Page",
20418     /**
20419      * Customizable piece of the default paging text (defaults to "of %0")
20420      * @type String
20421      */
20422     afterPageText : "of {0}",
20423     /**
20424      * Customizable piece of the default paging text (defaults to "First Page")
20425      * @type String
20426      */
20427     firstText : "First Page",
20428     /**
20429      * Customizable piece of the default paging text (defaults to "Previous Page")
20430      * @type String
20431      */
20432     prevText : "Previous Page",
20433     /**
20434      * Customizable piece of the default paging text (defaults to "Next Page")
20435      * @type String
20436      */
20437     nextText : "Next Page",
20438     /**
20439      * Customizable piece of the default paging text (defaults to "Last Page")
20440      * @type String
20441      */
20442     lastText : "Last Page",
20443     /**
20444      * Customizable piece of the default paging text (defaults to "Refresh")
20445      * @type String
20446      */
20447     refreshText : "Refresh",
20448
20449     buttons : false,
20450     // private
20451     onRender : function(ct, position) 
20452     {
20453         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20454         this.navgroup.parentId = this.id;
20455         this.navgroup.onRender(this.el, null);
20456         // add the buttons to the navgroup
20457         
20458         if(this.displayInfo){
20459             Roo.log(this.el.select('ul.navbar-nav',true).first());
20460             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20461             this.displayEl = this.el.select('.x-paging-info', true).first();
20462 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20463 //            this.displayEl = navel.el.select('span',true).first();
20464         }
20465         
20466         var _this = this;
20467         
20468         if(this.buttons){
20469             Roo.each(_this.buttons, function(e){
20470                Roo.factory(e).onRender(_this.el, null);
20471             });
20472         }
20473             
20474         Roo.each(_this.toolbarItems, function(e) {
20475             _this.navgroup.addItem(e);
20476         });
20477         
20478         
20479         this.first = this.navgroup.addItem({
20480             tooltip: this.firstText,
20481             cls: "prev",
20482             icon : 'fa fa-backward',
20483             disabled: true,
20484             preventDefault: true,
20485             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20486         });
20487         
20488         this.prev =  this.navgroup.addItem({
20489             tooltip: this.prevText,
20490             cls: "prev",
20491             icon : 'fa fa-step-backward',
20492             disabled: true,
20493             preventDefault: true,
20494             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
20495         });
20496     //this.addSeparator();
20497         
20498         
20499         var field = this.navgroup.addItem( {
20500             tagtype : 'span',
20501             cls : 'x-paging-position',
20502             
20503             html : this.beforePageText  +
20504                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20505                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
20506          } ); //?? escaped?
20507         
20508         this.field = field.el.select('input', true).first();
20509         this.field.on("keydown", this.onPagingKeydown, this);
20510         this.field.on("focus", function(){this.dom.select();});
20511     
20512     
20513         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
20514         //this.field.setHeight(18);
20515         //this.addSeparator();
20516         this.next = this.navgroup.addItem({
20517             tooltip: this.nextText,
20518             cls: "next",
20519             html : ' <i class="fa fa-step-forward">',
20520             disabled: true,
20521             preventDefault: true,
20522             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
20523         });
20524         this.last = this.navgroup.addItem({
20525             tooltip: this.lastText,
20526             icon : 'fa fa-forward',
20527             cls: "next",
20528             disabled: true,
20529             preventDefault: true,
20530             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
20531         });
20532     //this.addSeparator();
20533         this.loading = this.navgroup.addItem({
20534             tooltip: this.refreshText,
20535             icon: 'fa fa-refresh',
20536             preventDefault: true,
20537             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20538         });
20539
20540     },
20541
20542     // private
20543     updateInfo : function(){
20544         if(this.displayEl){
20545             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20546             var msg = count == 0 ?
20547                 this.emptyMsg :
20548                 String.format(
20549                     this.displayMsg,
20550                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
20551                 );
20552             this.displayEl.update(msg);
20553         }
20554     },
20555
20556     // private
20557     onLoad : function(ds, r, o){
20558        this.cursor = o.params ? o.params.start : 0;
20559        var d = this.getPageData(),
20560             ap = d.activePage,
20561             ps = d.pages;
20562         
20563        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20564        this.field.dom.value = ap;
20565        this.first.setDisabled(ap == 1);
20566        this.prev.setDisabled(ap == 1);
20567        this.next.setDisabled(ap == ps);
20568        this.last.setDisabled(ap == ps);
20569        this.loading.enable();
20570        this.updateInfo();
20571     },
20572
20573     // private
20574     getPageData : function(){
20575         var total = this.ds.getTotalCount();
20576         return {
20577             total : total,
20578             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20579             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20580         };
20581     },
20582
20583     // private
20584     onLoadError : function(){
20585         this.loading.enable();
20586     },
20587
20588     // private
20589     onPagingKeydown : function(e){
20590         var k = e.getKey();
20591         var d = this.getPageData();
20592         if(k == e.RETURN){
20593             var v = this.field.dom.value, pageNum;
20594             if(!v || isNaN(pageNum = parseInt(v, 10))){
20595                 this.field.dom.value = d.activePage;
20596                 return;
20597             }
20598             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20599             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20600             e.stopEvent();
20601         }
20602         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))
20603         {
20604           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20605           this.field.dom.value = pageNum;
20606           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20607           e.stopEvent();
20608         }
20609         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20610         {
20611           var v = this.field.dom.value, pageNum; 
20612           var increment = (e.shiftKey) ? 10 : 1;
20613           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20614             increment *= -1;
20615           if(!v || isNaN(pageNum = parseInt(v, 10))) {
20616             this.field.dom.value = d.activePage;
20617             return;
20618           }
20619           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20620           {
20621             this.field.dom.value = parseInt(v, 10) + increment;
20622             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20623             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20624           }
20625           e.stopEvent();
20626         }
20627     },
20628
20629     // private
20630     beforeLoad : function(){
20631         if(this.loading){
20632             this.loading.disable();
20633         }
20634     },
20635
20636     // private
20637     onClick : function(which){
20638         
20639         var ds = this.ds;
20640         if (!ds) {
20641             return;
20642         }
20643         
20644         switch(which){
20645             case "first":
20646                 ds.load({params:{start: 0, limit: this.pageSize}});
20647             break;
20648             case "prev":
20649                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20650             break;
20651             case "next":
20652                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20653             break;
20654             case "last":
20655                 var total = ds.getTotalCount();
20656                 var extra = total % this.pageSize;
20657                 var lastStart = extra ? (total - extra) : total-this.pageSize;
20658                 ds.load({params:{start: lastStart, limit: this.pageSize}});
20659             break;
20660             case "refresh":
20661                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20662             break;
20663         }
20664     },
20665
20666     /**
20667      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20668      * @param {Roo.data.Store} store The data store to unbind
20669      */
20670     unbind : function(ds){
20671         ds.un("beforeload", this.beforeLoad, this);
20672         ds.un("load", this.onLoad, this);
20673         ds.un("loadexception", this.onLoadError, this);
20674         ds.un("remove", this.updateInfo, this);
20675         ds.un("add", this.updateInfo, this);
20676         this.ds = undefined;
20677     },
20678
20679     /**
20680      * Binds the paging toolbar to the specified {@link Roo.data.Store}
20681      * @param {Roo.data.Store} store The data store to bind
20682      */
20683     bind : function(ds){
20684         ds.on("beforeload", this.beforeLoad, this);
20685         ds.on("load", this.onLoad, this);
20686         ds.on("loadexception", this.onLoadError, this);
20687         ds.on("remove", this.updateInfo, this);
20688         ds.on("add", this.updateInfo, this);
20689         this.ds = ds;
20690     }
20691 });/*
20692  * - LGPL
20693  *
20694  * element
20695  * 
20696  */
20697
20698 /**
20699  * @class Roo.bootstrap.MessageBar
20700  * @extends Roo.bootstrap.Component
20701  * Bootstrap MessageBar class
20702  * @cfg {String} html contents of the MessageBar
20703  * @cfg {String} weight (info | success | warning | danger) default info
20704  * @cfg {String} beforeClass insert the bar before the given class
20705  * @cfg {Boolean} closable (true | false) default false
20706  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20707  * 
20708  * @constructor
20709  * Create a new Element
20710  * @param {Object} config The config object
20711  */
20712
20713 Roo.bootstrap.MessageBar = function(config){
20714     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20715 };
20716
20717 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
20718     
20719     html: '',
20720     weight: 'info',
20721     closable: false,
20722     fixed: false,
20723     beforeClass: 'bootstrap-sticky-wrap',
20724     
20725     getAutoCreate : function(){
20726         
20727         var cfg = {
20728             tag: 'div',
20729             cls: 'alert alert-dismissable alert-' + this.weight,
20730             cn: [
20731                 {
20732                     tag: 'span',
20733                     cls: 'message',
20734                     html: this.html || ''
20735                 }
20736             ]
20737         }
20738         
20739         if(this.fixed){
20740             cfg.cls += ' alert-messages-fixed';
20741         }
20742         
20743         if(this.closable){
20744             cfg.cn.push({
20745                 tag: 'button',
20746                 cls: 'close',
20747                 html: 'x'
20748             });
20749         }
20750         
20751         return cfg;
20752     },
20753     
20754     onRender : function(ct, position)
20755     {
20756         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20757         
20758         if(!this.el){
20759             var cfg = Roo.apply({},  this.getAutoCreate());
20760             cfg.id = Roo.id();
20761             
20762             if (this.cls) {
20763                 cfg.cls += ' ' + this.cls;
20764             }
20765             if (this.style) {
20766                 cfg.style = this.style;
20767             }
20768             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20769             
20770             this.el.setVisibilityMode(Roo.Element.DISPLAY);
20771         }
20772         
20773         this.el.select('>button.close').on('click', this.hide, this);
20774         
20775     },
20776     
20777     show : function()
20778     {
20779         if (!this.rendered) {
20780             this.render();
20781         }
20782         
20783         this.el.show();
20784         
20785         this.fireEvent('show', this);
20786         
20787     },
20788     
20789     hide : function()
20790     {
20791         if (!this.rendered) {
20792             this.render();
20793         }
20794         
20795         this.el.hide();
20796         
20797         this.fireEvent('hide', this);
20798     },
20799     
20800     update : function()
20801     {
20802 //        var e = this.el.dom.firstChild;
20803 //        
20804 //        if(this.closable){
20805 //            e = e.nextSibling;
20806 //        }
20807 //        
20808 //        e.data = this.html || '';
20809
20810         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20811     }
20812    
20813 });
20814
20815  
20816
20817      /*
20818  * - LGPL
20819  *
20820  * Graph
20821  * 
20822  */
20823
20824
20825 /**
20826  * @class Roo.bootstrap.Graph
20827  * @extends Roo.bootstrap.Component
20828  * Bootstrap Graph class
20829 > Prameters
20830  -sm {number} sm 4
20831  -md {number} md 5
20832  @cfg {String} graphtype  bar | vbar | pie
20833  @cfg {number} g_x coodinator | centre x (pie)
20834  @cfg {number} g_y coodinator | centre y (pie)
20835  @cfg {number} g_r radius (pie)
20836  @cfg {number} g_height height of the chart (respected by all elements in the set)
20837  @cfg {number} g_width width of the chart (respected by all elements in the set)
20838  @cfg {Object} title The title of the chart
20839     
20840  -{Array}  values
20841  -opts (object) options for the chart 
20842      o {
20843      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20844      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20845      o vgutter (number)
20846      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.
20847      o stacked (boolean) whether or not to tread values as in a stacked bar chart
20848      o to
20849      o stretch (boolean)
20850      o }
20851  -opts (object) options for the pie
20852      o{
20853      o cut
20854      o startAngle (number)
20855      o endAngle (number)
20856      } 
20857  *
20858  * @constructor
20859  * Create a new Input
20860  * @param {Object} config The config object
20861  */
20862
20863 Roo.bootstrap.Graph = function(config){
20864     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20865     
20866     this.addEvents({
20867         // img events
20868         /**
20869          * @event click
20870          * The img click event for the img.
20871          * @param {Roo.EventObject} e
20872          */
20873         "click" : true
20874     });
20875 };
20876
20877 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
20878     
20879     sm: 4,
20880     md: 5,
20881     graphtype: 'bar',
20882     g_height: 250,
20883     g_width: 400,
20884     g_x: 50,
20885     g_y: 50,
20886     g_r: 30,
20887     opts:{
20888         //g_colors: this.colors,
20889         g_type: 'soft',
20890         g_gutter: '20%'
20891
20892     },
20893     title : false,
20894
20895     getAutoCreate : function(){
20896         
20897         var cfg = {
20898             tag: 'div',
20899             html : null
20900         }
20901         
20902         
20903         return  cfg;
20904     },
20905
20906     onRender : function(ct,position){
20907         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20908         this.raphael = Raphael(this.el.dom);
20909         
20910                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20911                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20912                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20913                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20914                 /*
20915                 r.text(160, 10, "Single Series Chart").attr(txtattr);
20916                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20917                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20918                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20919                 
20920                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20921                 r.barchart(330, 10, 300, 220, data1);
20922                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20923                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20924                 */
20925                 
20926                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20927                 // r.barchart(30, 30, 560, 250,  xdata, {
20928                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20929                 //     axis : "0 0 1 1",
20930                 //     axisxlabels :  xdata
20931                 //     //yvalues : cols,
20932                    
20933                 // });
20934 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20935 //        
20936 //        this.load(null,xdata,{
20937 //                axis : "0 0 1 1",
20938 //                axisxlabels :  xdata
20939 //                });
20940
20941     },
20942
20943     load : function(graphtype,xdata,opts){
20944         this.raphael.clear();
20945         if(!graphtype) {
20946             graphtype = this.graphtype;
20947         }
20948         if(!opts){
20949             opts = this.opts;
20950         }
20951         var r = this.raphael,
20952             fin = function () {
20953                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20954             },
20955             fout = function () {
20956                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20957             },
20958             pfin = function() {
20959                 this.sector.stop();
20960                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20961
20962                 if (this.label) {
20963                     this.label[0].stop();
20964                     this.label[0].attr({ r: 7.5 });
20965                     this.label[1].attr({ "font-weight": 800 });
20966                 }
20967             },
20968             pfout = function() {
20969                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20970
20971                 if (this.label) {
20972                     this.label[0].animate({ r: 5 }, 500, "bounce");
20973                     this.label[1].attr({ "font-weight": 400 });
20974                 }
20975             };
20976
20977         switch(graphtype){
20978             case 'bar':
20979                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20980                 break;
20981             case 'hbar':
20982                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20983                 break;
20984             case 'pie':
20985 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
20986 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20987 //            
20988                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20989                 
20990                 break;
20991
20992         }
20993         
20994         if(this.title){
20995             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
20996         }
20997         
20998     },
20999     
21000     setTitle: function(o)
21001     {
21002         this.title = o;
21003     },
21004     
21005     initEvents: function() {
21006         
21007         if(!this.href){
21008             this.el.on('click', this.onClick, this);
21009         }
21010     },
21011     
21012     onClick : function(e)
21013     {
21014         Roo.log('img onclick');
21015         this.fireEvent('click', this, e);
21016     }
21017    
21018 });
21019
21020  
21021 /*
21022  * - LGPL
21023  *
21024  * numberBox
21025  * 
21026  */
21027 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21028
21029 /**
21030  * @class Roo.bootstrap.dash.NumberBox
21031  * @extends Roo.bootstrap.Component
21032  * Bootstrap NumberBox class
21033  * @cfg {String} headline Box headline
21034  * @cfg {String} content Box content
21035  * @cfg {String} icon Box icon
21036  * @cfg {String} footer Footer text
21037  * @cfg {String} fhref Footer href
21038  * 
21039  * @constructor
21040  * Create a new NumberBox
21041  * @param {Object} config The config object
21042  */
21043
21044
21045 Roo.bootstrap.dash.NumberBox = function(config){
21046     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21047     
21048 };
21049
21050 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
21051     
21052     headline : '',
21053     content : '',
21054     icon : '',
21055     footer : '',
21056     fhref : '',
21057     ficon : '',
21058     
21059     getAutoCreate : function(){
21060         
21061         var cfg = {
21062             tag : 'div',
21063             cls : 'small-box ',
21064             cn : [
21065                 {
21066                     tag : 'div',
21067                     cls : 'inner',
21068                     cn :[
21069                         {
21070                             tag : 'h3',
21071                             cls : 'roo-headline',
21072                             html : this.headline
21073                         },
21074                         {
21075                             tag : 'p',
21076                             cls : 'roo-content',
21077                             html : this.content
21078                         }
21079                     ]
21080                 }
21081             ]
21082         }
21083         
21084         if(this.icon){
21085             cfg.cn.push({
21086                 tag : 'div',
21087                 cls : 'icon',
21088                 cn :[
21089                     {
21090                         tag : 'i',
21091                         cls : 'ion ' + this.icon
21092                     }
21093                 ]
21094             });
21095         }
21096         
21097         if(this.footer){
21098             var footer = {
21099                 tag : 'a',
21100                 cls : 'small-box-footer',
21101                 href : this.fhref || '#',
21102                 html : this.footer
21103             };
21104             
21105             cfg.cn.push(footer);
21106             
21107         }
21108         
21109         return  cfg;
21110     },
21111
21112     onRender : function(ct,position){
21113         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21114
21115
21116        
21117                 
21118     },
21119
21120     setHeadline: function (value)
21121     {
21122         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21123     },
21124     
21125     setFooter: function (value, href)
21126     {
21127         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21128         
21129         if(href){
21130             this.el.select('a.small-box-footer',true).first().attr('href', href);
21131         }
21132         
21133     },
21134
21135     setContent: function (value)
21136     {
21137         this.el.select('.roo-content',true).first().dom.innerHTML = value;
21138     },
21139
21140     initEvents: function() 
21141     {   
21142         
21143     }
21144     
21145 });
21146
21147  
21148 /*
21149  * - LGPL
21150  *
21151  * TabBox
21152  * 
21153  */
21154 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21155
21156 /**
21157  * @class Roo.bootstrap.dash.TabBox
21158  * @extends Roo.bootstrap.Component
21159  * Bootstrap TabBox class
21160  * @cfg {String} title Title of the TabBox
21161  * @cfg {String} icon Icon of the TabBox
21162  * @cfg {Boolean} showtabs (true|false) show the tabs default true
21163  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21164  * 
21165  * @constructor
21166  * Create a new TabBox
21167  * @param {Object} config The config object
21168  */
21169
21170
21171 Roo.bootstrap.dash.TabBox = function(config){
21172     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21173     this.addEvents({
21174         // raw events
21175         /**
21176          * @event addpane
21177          * When a pane is added
21178          * @param {Roo.bootstrap.dash.TabPane} pane
21179          */
21180         "addpane" : true,
21181         /**
21182          * @event activatepane
21183          * When a pane is activated
21184          * @param {Roo.bootstrap.dash.TabPane} pane
21185          */
21186         "activatepane" : true
21187         
21188          
21189     });
21190     
21191     this.panes = [];
21192 };
21193
21194 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
21195
21196     title : '',
21197     icon : false,
21198     showtabs : true,
21199     tabScrollable : false,
21200     
21201     getChildContainer : function()
21202     {
21203         return this.el.select('.tab-content', true).first();
21204     },
21205     
21206     getAutoCreate : function(){
21207         
21208         var header = {
21209             tag: 'li',
21210             cls: 'pull-left header',
21211             html: this.title,
21212             cn : []
21213         };
21214         
21215         if(this.icon){
21216             header.cn.push({
21217                 tag: 'i',
21218                 cls: 'fa ' + this.icon
21219             });
21220         }
21221         
21222         var h = {
21223             tag: 'ul',
21224             cls: 'nav nav-tabs pull-right',
21225             cn: [
21226                 header
21227             ]
21228         };
21229         
21230         if(this.tabScrollable){
21231             h = {
21232                 tag: 'div',
21233                 cls: 'tab-header',
21234                 cn: [
21235                     {
21236                         tag: 'ul',
21237                         cls: 'nav nav-tabs pull-right',
21238                         cn: [
21239                             header
21240                         ]
21241                     }
21242                 ]
21243             }
21244         }
21245         
21246         var cfg = {
21247             tag: 'div',
21248             cls: 'nav-tabs-custom',
21249             cn: [
21250                 h,
21251                 {
21252                     tag: 'div',
21253                     cls: 'tab-content no-padding',
21254                     cn: []
21255                 }
21256             ]
21257         }
21258
21259         return  cfg;
21260     },
21261     initEvents : function()
21262     {
21263         //Roo.log('add add pane handler');
21264         this.on('addpane', this.onAddPane, this);
21265     },
21266      /**
21267      * Updates the box title
21268      * @param {String} html to set the title to.
21269      */
21270     setTitle : function(value)
21271     {
21272         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21273     },
21274     onAddPane : function(pane)
21275     {
21276         this.panes.push(pane);
21277         //Roo.log('addpane');
21278         //Roo.log(pane);
21279         // tabs are rendere left to right..
21280         if(!this.showtabs){
21281             return;
21282         }
21283         
21284         var ctr = this.el.select('.nav-tabs', true).first();
21285          
21286          
21287         var existing = ctr.select('.nav-tab',true);
21288         var qty = existing.getCount();;
21289         
21290         
21291         var tab = ctr.createChild({
21292             tag : 'li',
21293             cls : 'nav-tab' + (qty ? '' : ' active'),
21294             cn : [
21295                 {
21296                     tag : 'a',
21297                     href:'#',
21298                     html : pane.title
21299                 }
21300             ]
21301         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21302         pane.tab = tab;
21303         
21304         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21305         if (!qty) {
21306             pane.el.addClass('active');
21307         }
21308         
21309                 
21310     },
21311     onTabClick : function(ev,un,ob,pane)
21312     {
21313         //Roo.log('tab - prev default');
21314         ev.preventDefault();
21315         
21316         
21317         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21318         pane.tab.addClass('active');
21319         //Roo.log(pane.title);
21320         this.getChildContainer().select('.tab-pane',true).removeClass('active');
21321         // technically we should have a deactivate event.. but maybe add later.
21322         // and it should not de-activate the selected tab...
21323         this.fireEvent('activatepane', pane);
21324         pane.el.addClass('active');
21325         pane.fireEvent('activate');
21326         
21327         
21328     },
21329     
21330     getActivePane : function()
21331     {
21332         var r = false;
21333         Roo.each(this.panes, function(p) {
21334             if(p.el.hasClass('active')){
21335                 r = p;
21336                 return false;
21337             }
21338             
21339             return;
21340         });
21341         
21342         return r;
21343     }
21344     
21345     
21346 });
21347
21348  
21349 /*
21350  * - LGPL
21351  *
21352  * Tab pane
21353  * 
21354  */
21355 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21356 /**
21357  * @class Roo.bootstrap.TabPane
21358  * @extends Roo.bootstrap.Component
21359  * Bootstrap TabPane class
21360  * @cfg {Boolean} active (false | true) Default false
21361  * @cfg {String} title title of panel
21362
21363  * 
21364  * @constructor
21365  * Create a new TabPane
21366  * @param {Object} config The config object
21367  */
21368
21369 Roo.bootstrap.dash.TabPane = function(config){
21370     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21371     
21372     this.addEvents({
21373         // raw events
21374         /**
21375          * @event activate
21376          * When a pane is activated
21377          * @param {Roo.bootstrap.dash.TabPane} pane
21378          */
21379         "activate" : true
21380          
21381     });
21382 };
21383
21384 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
21385     
21386     active : false,
21387     title : '',
21388     
21389     // the tabBox that this is attached to.
21390     tab : false,
21391      
21392     getAutoCreate : function() 
21393     {
21394         var cfg = {
21395             tag: 'div',
21396             cls: 'tab-pane'
21397         }
21398         
21399         if(this.active){
21400             cfg.cls += ' active';
21401         }
21402         
21403         return cfg;
21404     },
21405     initEvents  : function()
21406     {
21407         //Roo.log('trigger add pane handler');
21408         this.parent().fireEvent('addpane', this)
21409     },
21410     
21411      /**
21412      * Updates the tab title 
21413      * @param {String} html to set the title to.
21414      */
21415     setTitle: function(str)
21416     {
21417         if (!this.tab) {
21418             return;
21419         }
21420         this.title = str;
21421         this.tab.select('a', true).first().dom.innerHTML = str;
21422         
21423     }
21424     
21425     
21426     
21427 });
21428
21429  
21430
21431
21432  /*
21433  * - LGPL
21434  *
21435  * menu
21436  * 
21437  */
21438 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21439
21440 /**
21441  * @class Roo.bootstrap.menu.Menu
21442  * @extends Roo.bootstrap.Component
21443  * Bootstrap Menu class - container for Menu
21444  * @cfg {String} html Text of the menu
21445  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21446  * @cfg {String} icon Font awesome icon
21447  * @cfg {String} pos Menu align to (top | bottom) default bottom
21448  * 
21449  * 
21450  * @constructor
21451  * Create a new Menu
21452  * @param {Object} config The config object
21453  */
21454
21455
21456 Roo.bootstrap.menu.Menu = function(config){
21457     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21458     
21459     this.addEvents({
21460         /**
21461          * @event beforeshow
21462          * Fires before this menu is displayed
21463          * @param {Roo.bootstrap.menu.Menu} this
21464          */
21465         beforeshow : true,
21466         /**
21467          * @event beforehide
21468          * Fires before this menu is hidden
21469          * @param {Roo.bootstrap.menu.Menu} this
21470          */
21471         beforehide : true,
21472         /**
21473          * @event show
21474          * Fires after this menu is displayed
21475          * @param {Roo.bootstrap.menu.Menu} this
21476          */
21477         show : true,
21478         /**
21479          * @event hide
21480          * Fires after this menu is hidden
21481          * @param {Roo.bootstrap.menu.Menu} this
21482          */
21483         hide : true,
21484         /**
21485          * @event click
21486          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21487          * @param {Roo.bootstrap.menu.Menu} this
21488          * @param {Roo.EventObject} e
21489          */
21490         click : true
21491     });
21492     
21493 };
21494
21495 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
21496     
21497     submenu : false,
21498     html : '',
21499     weight : 'default',
21500     icon : false,
21501     pos : 'bottom',
21502     
21503     
21504     getChildContainer : function() {
21505         if(this.isSubMenu){
21506             return this.el;
21507         }
21508         
21509         return this.el.select('ul.dropdown-menu', true).first();  
21510     },
21511     
21512     getAutoCreate : function()
21513     {
21514         var text = [
21515             {
21516                 tag : 'span',
21517                 cls : 'roo-menu-text',
21518                 html : this.html
21519             }
21520         ];
21521         
21522         if(this.icon){
21523             text.unshift({
21524                 tag : 'i',
21525                 cls : 'fa ' + this.icon
21526             })
21527         }
21528         
21529         
21530         var cfg = {
21531             tag : 'div',
21532             cls : 'btn-group',
21533             cn : [
21534                 {
21535                     tag : 'button',
21536                     cls : 'dropdown-button btn btn-' + this.weight,
21537                     cn : text
21538                 },
21539                 {
21540                     tag : 'button',
21541                     cls : 'dropdown-toggle btn btn-' + this.weight,
21542                     cn : [
21543                         {
21544                             tag : 'span',
21545                             cls : 'caret'
21546                         }
21547                     ]
21548                 },
21549                 {
21550                     tag : 'ul',
21551                     cls : 'dropdown-menu'
21552                 }
21553             ]
21554             
21555         };
21556         
21557         if(this.pos == 'top'){
21558             cfg.cls += ' dropup';
21559         }
21560         
21561         if(this.isSubMenu){
21562             cfg = {
21563                 tag : 'ul',
21564                 cls : 'dropdown-menu'
21565             }
21566         }
21567         
21568         return cfg;
21569     },
21570     
21571     onRender : function(ct, position)
21572     {
21573         this.isSubMenu = ct.hasClass('dropdown-submenu');
21574         
21575         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21576     },
21577     
21578     initEvents : function() 
21579     {
21580         if(this.isSubMenu){
21581             return;
21582         }
21583         
21584         this.hidden = true;
21585         
21586         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21587         this.triggerEl.on('click', this.onTriggerPress, this);
21588         
21589         this.buttonEl = this.el.select('button.dropdown-button', true).first();
21590         this.buttonEl.on('click', this.onClick, this);
21591         
21592     },
21593     
21594     list : function()
21595     {
21596         if(this.isSubMenu){
21597             return this.el;
21598         }
21599         
21600         return this.el.select('ul.dropdown-menu', true).first();
21601     },
21602     
21603     onClick : function(e)
21604     {
21605         this.fireEvent("click", this, e);
21606     },
21607     
21608     onTriggerPress  : function(e)
21609     {   
21610         if (this.isVisible()) {
21611             this.hide();
21612         } else {
21613             this.show();
21614         }
21615     },
21616     
21617     isVisible : function(){
21618         return !this.hidden;
21619     },
21620     
21621     show : function()
21622     {
21623         this.fireEvent("beforeshow", this);
21624         
21625         this.hidden = false;
21626         this.el.addClass('open');
21627         
21628         Roo.get(document).on("mouseup", this.onMouseUp, this);
21629         
21630         this.fireEvent("show", this);
21631         
21632         
21633     },
21634     
21635     hide : function()
21636     {
21637         this.fireEvent("beforehide", this);
21638         
21639         this.hidden = true;
21640         this.el.removeClass('open');
21641         
21642         Roo.get(document).un("mouseup", this.onMouseUp);
21643         
21644         this.fireEvent("hide", this);
21645     },
21646     
21647     onMouseUp : function()
21648     {
21649         this.hide();
21650     }
21651     
21652 });
21653
21654  
21655  /*
21656  * - LGPL
21657  *
21658  * menu item
21659  * 
21660  */
21661 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21662
21663 /**
21664  * @class Roo.bootstrap.menu.Item
21665  * @extends Roo.bootstrap.Component
21666  * Bootstrap MenuItem class
21667  * @cfg {Boolean} submenu (true | false) default false
21668  * @cfg {String} html text of the item
21669  * @cfg {String} href the link
21670  * @cfg {Boolean} disable (true | false) default false
21671  * @cfg {Boolean} preventDefault (true | false) default true
21672  * @cfg {String} icon Font awesome icon
21673  * @cfg {String} pos Submenu align to (left | right) default right 
21674  * 
21675  * 
21676  * @constructor
21677  * Create a new Item
21678  * @param {Object} config The config object
21679  */
21680
21681
21682 Roo.bootstrap.menu.Item = function(config){
21683     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21684     this.addEvents({
21685         /**
21686          * @event mouseover
21687          * Fires when the mouse is hovering over this menu
21688          * @param {Roo.bootstrap.menu.Item} this
21689          * @param {Roo.EventObject} e
21690          */
21691         mouseover : true,
21692         /**
21693          * @event mouseout
21694          * Fires when the mouse exits this menu
21695          * @param {Roo.bootstrap.menu.Item} this
21696          * @param {Roo.EventObject} e
21697          */
21698         mouseout : true,
21699         // raw events
21700         /**
21701          * @event click
21702          * The raw click event for the entire grid.
21703          * @param {Roo.EventObject} e
21704          */
21705         click : true
21706     });
21707 };
21708
21709 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
21710     
21711     submenu : false,
21712     href : '',
21713     html : '',
21714     preventDefault: true,
21715     disable : false,
21716     icon : false,
21717     pos : 'right',
21718     
21719     getAutoCreate : function()
21720     {
21721         var text = [
21722             {
21723                 tag : 'span',
21724                 cls : 'roo-menu-item-text',
21725                 html : this.html
21726             }
21727         ];
21728         
21729         if(this.icon){
21730             text.unshift({
21731                 tag : 'i',
21732                 cls : 'fa ' + this.icon
21733             })
21734         }
21735         
21736         var cfg = {
21737             tag : 'li',
21738             cn : [
21739                 {
21740                     tag : 'a',
21741                     href : this.href || '#',
21742                     cn : text
21743                 }
21744             ]
21745         };
21746         
21747         if(this.disable){
21748             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21749         }
21750         
21751         if(this.submenu){
21752             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21753             
21754             if(this.pos == 'left'){
21755                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21756             }
21757         }
21758         
21759         return cfg;
21760     },
21761     
21762     initEvents : function() 
21763     {
21764         this.el.on('mouseover', this.onMouseOver, this);
21765         this.el.on('mouseout', this.onMouseOut, this);
21766         
21767         this.el.select('a', true).first().on('click', this.onClick, this);
21768         
21769     },
21770     
21771     onClick : function(e)
21772     {
21773         if(this.preventDefault){
21774             e.preventDefault();
21775         }
21776         
21777         this.fireEvent("click", this, e);
21778     },
21779     
21780     onMouseOver : function(e)
21781     {
21782         if(this.submenu && this.pos == 'left'){
21783             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21784         }
21785         
21786         this.fireEvent("mouseover", this, e);
21787     },
21788     
21789     onMouseOut : function(e)
21790     {
21791         this.fireEvent("mouseout", this, e);
21792     }
21793 });
21794
21795  
21796
21797  /*
21798  * - LGPL
21799  *
21800  * menu separator
21801  * 
21802  */
21803 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21804
21805 /**
21806  * @class Roo.bootstrap.menu.Separator
21807  * @extends Roo.bootstrap.Component
21808  * Bootstrap Separator class
21809  * 
21810  * @constructor
21811  * Create a new Separator
21812  * @param {Object} config The config object
21813  */
21814
21815
21816 Roo.bootstrap.menu.Separator = function(config){
21817     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21818 };
21819
21820 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
21821     
21822     getAutoCreate : function(){
21823         var cfg = {
21824             tag : 'li',
21825             cls: 'divider'
21826         };
21827         
21828         return cfg;
21829     }
21830    
21831 });
21832
21833  
21834
21835  /*
21836  * - LGPL
21837  *
21838  * Tooltip
21839  * 
21840  */
21841
21842 /**
21843  * @class Roo.bootstrap.Tooltip
21844  * Bootstrap Tooltip class
21845  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21846  * to determine which dom element triggers the tooltip.
21847  * 
21848  * It needs to add support for additional attributes like tooltip-position
21849  * 
21850  * @constructor
21851  * Create a new Toolti
21852  * @param {Object} config The config object
21853  */
21854
21855 Roo.bootstrap.Tooltip = function(config){
21856     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21857 };
21858
21859 Roo.apply(Roo.bootstrap.Tooltip, {
21860     /**
21861      * @function init initialize tooltip monitoring.
21862      * @static
21863      */
21864     currentEl : false,
21865     currentTip : false,
21866     currentRegion : false,
21867     
21868     //  init : delay?
21869     
21870     init : function()
21871     {
21872         Roo.get(document).on('mouseover', this.enter ,this);
21873         Roo.get(document).on('mouseout', this.leave, this);
21874          
21875         
21876         this.currentTip = new Roo.bootstrap.Tooltip();
21877     },
21878     
21879     enter : function(ev)
21880     {
21881         var dom = ev.getTarget();
21882         
21883         //Roo.log(['enter',dom]);
21884         var el = Roo.fly(dom);
21885         if (this.currentEl) {
21886             //Roo.log(dom);
21887             //Roo.log(this.currentEl);
21888             //Roo.log(this.currentEl.contains(dom));
21889             if (this.currentEl == el) {
21890                 return;
21891             }
21892             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21893                 return;
21894             }
21895
21896         }
21897         
21898         
21899         
21900         if (this.currentTip.el) {
21901             this.currentTip.el.hide(); // force hiding...
21902         }    
21903         //Roo.log(ev);
21904         var bindEl = el;
21905         
21906         // you can not look for children, as if el is the body.. then everythign is the child..
21907         if (!el.attr('tooltip')) { //
21908             if (!el.select("[tooltip]").elements.length) {
21909                 return;
21910             }
21911             // is the mouse over this child...?
21912             bindEl = el.select("[tooltip]").first();
21913             var xy = ev.getXY();
21914             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
21915                 //Roo.log("not in region.");
21916                 return;
21917             }
21918             //Roo.log("child element over..");
21919             
21920         }
21921         this.currentEl = bindEl;
21922         this.currentTip.bind(bindEl);
21923         this.currentRegion = Roo.lib.Region.getRegion(dom);
21924         this.currentTip.enter();
21925         
21926     },
21927     leave : function(ev)
21928     {
21929         var dom = ev.getTarget();
21930         //Roo.log(['leave',dom]);
21931         if (!this.currentEl) {
21932             return;
21933         }
21934         
21935         
21936         if (dom != this.currentEl.dom) {
21937             return;
21938         }
21939         var xy = ev.getXY();
21940         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
21941             return;
21942         }
21943         // only activate leave if mouse cursor is outside... bounding box..
21944         
21945         
21946         
21947         
21948         if (this.currentTip) {
21949             this.currentTip.leave();
21950         }
21951         //Roo.log('clear currentEl');
21952         this.currentEl = false;
21953         
21954         
21955     },
21956     alignment : {
21957         'left' : ['r-l', [-2,0], 'right'],
21958         'right' : ['l-r', [2,0], 'left'],
21959         'bottom' : ['t-b', [0,2], 'top'],
21960         'top' : [ 'b-t', [0,-2], 'bottom']
21961     }
21962     
21963 });
21964
21965
21966 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
21967     
21968     
21969     bindEl : false,
21970     
21971     delay : null, // can be { show : 300 , hide: 500}
21972     
21973     timeout : null,
21974     
21975     hoverState : null, //???
21976     
21977     placement : 'bottom', 
21978     
21979     getAutoCreate : function(){
21980     
21981         var cfg = {
21982            cls : 'tooltip',
21983            role : 'tooltip',
21984            cn : [
21985                 {
21986                     cls : 'tooltip-arrow'
21987                 },
21988                 {
21989                     cls : 'tooltip-inner'
21990                 }
21991            ]
21992         };
21993         
21994         return cfg;
21995     },
21996     bind : function(el)
21997     {
21998         this.bindEl = el;
21999     },
22000       
22001     
22002     enter : function () {
22003        
22004         if (this.timeout != null) {
22005             clearTimeout(this.timeout);
22006         }
22007         
22008         this.hoverState = 'in';
22009          //Roo.log("enter - show");
22010         if (!this.delay || !this.delay.show) {
22011             this.show();
22012             return;
22013         }
22014         var _t = this;
22015         this.timeout = setTimeout(function () {
22016             if (_t.hoverState == 'in') {
22017                 _t.show();
22018             }
22019         }, this.delay.show);
22020     },
22021     leave : function()
22022     {
22023         clearTimeout(this.timeout);
22024     
22025         this.hoverState = 'out';
22026          if (!this.delay || !this.delay.hide) {
22027             this.hide();
22028             return;
22029         }
22030        
22031         var _t = this;
22032         this.timeout = setTimeout(function () {
22033             //Roo.log("leave - timeout");
22034             
22035             if (_t.hoverState == 'out') {
22036                 _t.hide();
22037                 Roo.bootstrap.Tooltip.currentEl = false;
22038             }
22039         }, delay);
22040     },
22041     
22042     show : function ()
22043     {
22044         if (!this.el) {
22045             this.render(document.body);
22046         }
22047         // set content.
22048         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22049         
22050         var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22051         
22052         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22053         
22054         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22055         
22056         var placement = typeof this.placement == 'function' ?
22057             this.placement.call(this, this.el, on_el) :
22058             this.placement;
22059             
22060         var autoToken = /\s?auto?\s?/i;
22061         var autoPlace = autoToken.test(placement);
22062         if (autoPlace) {
22063             placement = placement.replace(autoToken, '') || 'top';
22064         }
22065         
22066         //this.el.detach()
22067         //this.el.setXY([0,0]);
22068         this.el.show();
22069         //this.el.dom.style.display='block';
22070         this.el.addClass(placement);
22071         
22072         //this.el.appendTo(on_el);
22073         
22074         var p = this.getPosition();
22075         var box = this.el.getBox();
22076         
22077         if (autoPlace) {
22078             // fixme..
22079         }
22080         var align = Roo.bootstrap.Tooltip.alignment[placement];
22081         this.el.alignTo(this.bindEl, align[0],align[1]);
22082         //var arrow = this.el.select('.arrow',true).first();
22083         //arrow.set(align[2], 
22084         
22085         this.el.addClass('in fade');
22086         this.hoverState = null;
22087         
22088         if (this.el.hasClass('fade')) {
22089             // fade it?
22090         }
22091         
22092     },
22093     hide : function()
22094     {
22095          
22096         if (!this.el) {
22097             return;
22098         }
22099         //this.el.setXY([0,0]);
22100         this.el.removeClass('in');
22101         //this.el.hide();
22102         
22103     }
22104     
22105 });
22106  
22107
22108  /*
22109  * - LGPL
22110  *
22111  * Location Picker
22112  * 
22113  */
22114
22115 /**
22116  * @class Roo.bootstrap.LocationPicker
22117  * @extends Roo.bootstrap.Component
22118  * Bootstrap LocationPicker class
22119  * @cfg {Number} latitude Position when init default 0
22120  * @cfg {Number} longitude Position when init default 0
22121  * @cfg {Number} zoom default 15
22122  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22123  * @cfg {Boolean} mapTypeControl default false
22124  * @cfg {Boolean} disableDoubleClickZoom default false
22125  * @cfg {Boolean} scrollwheel default true
22126  * @cfg {Boolean} streetViewControl default false
22127  * @cfg {Number} radius default 0
22128  * @cfg {String} locationName
22129  * @cfg {Boolean} draggable default true
22130  * @cfg {Boolean} enableAutocomplete default false
22131  * @cfg {Boolean} enableReverseGeocode default true
22132  * @cfg {String} markerTitle
22133  * 
22134  * @constructor
22135  * Create a new LocationPicker
22136  * @param {Object} config The config object
22137  */
22138
22139
22140 Roo.bootstrap.LocationPicker = function(config){
22141     
22142     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22143     
22144     this.addEvents({
22145         /**
22146          * @event initial
22147          * Fires when the picker initialized.
22148          * @param {Roo.bootstrap.LocationPicker} this
22149          * @param {Google Location} location
22150          */
22151         initial : true,
22152         /**
22153          * @event positionchanged
22154          * Fires when the picker position changed.
22155          * @param {Roo.bootstrap.LocationPicker} this
22156          * @param {Google Location} location
22157          */
22158         positionchanged : true,
22159         /**
22160          * @event resize
22161          * Fires when the map resize.
22162          * @param {Roo.bootstrap.LocationPicker} this
22163          */
22164         resize : true,
22165         /**
22166          * @event show
22167          * Fires when the map show.
22168          * @param {Roo.bootstrap.LocationPicker} this
22169          */
22170         show : true,
22171         /**
22172          * @event hide
22173          * Fires when the map hide.
22174          * @param {Roo.bootstrap.LocationPicker} this
22175          */
22176         hide : true,
22177         /**
22178          * @event mapClick
22179          * Fires when click the map.
22180          * @param {Roo.bootstrap.LocationPicker} this
22181          * @param {Map event} e
22182          */
22183         mapClick : true,
22184         /**
22185          * @event mapRightClick
22186          * Fires when right click the map.
22187          * @param {Roo.bootstrap.LocationPicker} this
22188          * @param {Map event} e
22189          */
22190         mapRightClick : true,
22191         /**
22192          * @event markerClick
22193          * Fires when click the marker.
22194          * @param {Roo.bootstrap.LocationPicker} this
22195          * @param {Map event} e
22196          */
22197         markerClick : true,
22198         /**
22199          * @event markerRightClick
22200          * Fires when right click the marker.
22201          * @param {Roo.bootstrap.LocationPicker} this
22202          * @param {Map event} e
22203          */
22204         markerRightClick : true,
22205         /**
22206          * @event OverlayViewDraw
22207          * Fires when OverlayView Draw
22208          * @param {Roo.bootstrap.LocationPicker} this
22209          */
22210         OverlayViewDraw : true,
22211         /**
22212          * @event OverlayViewOnAdd
22213          * Fires when OverlayView Draw
22214          * @param {Roo.bootstrap.LocationPicker} this
22215          */
22216         OverlayViewOnAdd : true,
22217         /**
22218          * @event OverlayViewOnRemove
22219          * Fires when OverlayView Draw
22220          * @param {Roo.bootstrap.LocationPicker} this
22221          */
22222         OverlayViewOnRemove : true,
22223         /**
22224          * @event OverlayViewShow
22225          * Fires when OverlayView Draw
22226          * @param {Roo.bootstrap.LocationPicker} this
22227          * @param {Pixel} cpx
22228          */
22229         OverlayViewShow : true,
22230         /**
22231          * @event OverlayViewHide
22232          * Fires when OverlayView Draw
22233          * @param {Roo.bootstrap.LocationPicker} this
22234          */
22235         OverlayViewHide : true
22236     });
22237         
22238 };
22239
22240 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
22241     
22242     gMapContext: false,
22243     
22244     latitude: 0,
22245     longitude: 0,
22246     zoom: 15,
22247     mapTypeId: false,
22248     mapTypeControl: false,
22249     disableDoubleClickZoom: false,
22250     scrollwheel: true,
22251     streetViewControl: false,
22252     radius: 0,
22253     locationName: '',
22254     draggable: true,
22255     enableAutocomplete: false,
22256     enableReverseGeocode: true,
22257     markerTitle: '',
22258     
22259     getAutoCreate: function()
22260     {
22261
22262         var cfg = {
22263             tag: 'div',
22264             cls: 'roo-location-picker'
22265         };
22266         
22267         return cfg
22268     },
22269     
22270     initEvents: function(ct, position)
22271     {       
22272         if(!this.el.getWidth() || this.isApplied()){
22273             return;
22274         }
22275         
22276         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22277         
22278         this.initial();
22279     },
22280     
22281     initial: function()
22282     {
22283         if(!this.mapTypeId){
22284             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22285         }
22286         
22287         this.gMapContext = this.GMapContext();
22288         
22289         this.initOverlayView();
22290         
22291         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22292         
22293         var _this = this;
22294                 
22295         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22296             _this.setPosition(_this.gMapContext.marker.position);
22297         });
22298         
22299         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22300             _this.fireEvent('mapClick', this, event);
22301             
22302         });
22303
22304         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22305             _this.fireEvent('mapRightClick', this, event);
22306             
22307         });
22308         
22309         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22310             _this.fireEvent('markerClick', this, event);
22311             
22312         });
22313
22314         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22315             _this.fireEvent('markerRightClick', this, event);
22316             
22317         });
22318         
22319         this.setPosition(this.gMapContext.location);
22320         
22321         this.fireEvent('initial', this, this.gMapContext.location);
22322     },
22323     
22324     initOverlayView: function()
22325     {
22326         var _this = this;
22327         
22328         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22329             
22330             draw: function()
22331             {
22332                 _this.fireEvent('OverlayViewDraw', _this);
22333             },
22334             
22335             onAdd: function()
22336             {
22337                 _this.fireEvent('OverlayViewOnAdd', _this);
22338             },
22339             
22340             onRemove: function()
22341             {
22342                 _this.fireEvent('OverlayViewOnRemove', _this);
22343             },
22344             
22345             show: function(cpx)
22346             {
22347                 _this.fireEvent('OverlayViewShow', _this, cpx);
22348             },
22349             
22350             hide: function()
22351             {
22352                 _this.fireEvent('OverlayViewHide', _this);
22353             }
22354             
22355         });
22356     },
22357     
22358     fromLatLngToContainerPixel: function(event)
22359     {
22360         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22361     },
22362     
22363     isApplied: function() 
22364     {
22365         return this.getGmapContext() == false ? false : true;
22366     },
22367     
22368     getGmapContext: function() 
22369     {
22370         return this.gMapContext
22371     },
22372     
22373     GMapContext: function() 
22374     {
22375         var position = new google.maps.LatLng(this.latitude, this.longitude);
22376         
22377         var _map = new google.maps.Map(this.el.dom, {
22378             center: position,
22379             zoom: this.zoom,
22380             mapTypeId: this.mapTypeId,
22381             mapTypeControl: this.mapTypeControl,
22382             disableDoubleClickZoom: this.disableDoubleClickZoom,
22383             scrollwheel: this.scrollwheel,
22384             streetViewControl: this.streetViewControl,
22385             locationName: this.locationName,
22386             draggable: this.draggable,
22387             enableAutocomplete: this.enableAutocomplete,
22388             enableReverseGeocode: this.enableReverseGeocode
22389         });
22390         
22391         var _marker = new google.maps.Marker({
22392             position: position,
22393             map: _map,
22394             title: this.markerTitle,
22395             draggable: this.draggable
22396         });
22397         
22398         return {
22399             map: _map,
22400             marker: _marker,
22401             circle: null,
22402             location: position,
22403             radius: this.radius,
22404             locationName: this.locationName,
22405             addressComponents: {
22406                 formatted_address: null,
22407                 addressLine1: null,
22408                 addressLine2: null,
22409                 streetName: null,
22410                 streetNumber: null,
22411                 city: null,
22412                 district: null,
22413                 state: null,
22414                 stateOrProvince: null
22415             },
22416             settings: this,
22417             domContainer: this.el.dom,
22418             geodecoder: new google.maps.Geocoder()
22419         };
22420     },
22421     
22422     drawCircle: function(center, radius, options) 
22423     {
22424         if (this.gMapContext.circle != null) {
22425             this.gMapContext.circle.setMap(null);
22426         }
22427         if (radius > 0) {
22428             radius *= 1;
22429             options = Roo.apply({}, options, {
22430                 strokeColor: "#0000FF",
22431                 strokeOpacity: .35,
22432                 strokeWeight: 2,
22433                 fillColor: "#0000FF",
22434                 fillOpacity: .2
22435             });
22436             
22437             options.map = this.gMapContext.map;
22438             options.radius = radius;
22439             options.center = center;
22440             this.gMapContext.circle = new google.maps.Circle(options);
22441             return this.gMapContext.circle;
22442         }
22443         
22444         return null;
22445     },
22446     
22447     setPosition: function(location) 
22448     {
22449         this.gMapContext.location = location;
22450         this.gMapContext.marker.setPosition(location);
22451         this.gMapContext.map.panTo(location);
22452         this.drawCircle(location, this.gMapContext.radius, {});
22453         
22454         var _this = this;
22455         
22456         if (this.gMapContext.settings.enableReverseGeocode) {
22457             this.gMapContext.geodecoder.geocode({
22458                 latLng: this.gMapContext.location
22459             }, function(results, status) {
22460                 
22461                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22462                     _this.gMapContext.locationName = results[0].formatted_address;
22463                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22464                     
22465                     _this.fireEvent('positionchanged', this, location);
22466                 }
22467             });
22468             
22469             return;
22470         }
22471         
22472         this.fireEvent('positionchanged', this, location);
22473     },
22474     
22475     resize: function()
22476     {
22477         google.maps.event.trigger(this.gMapContext.map, "resize");
22478         
22479         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22480         
22481         this.fireEvent('resize', this);
22482     },
22483     
22484     setPositionByLatLng: function(latitude, longitude)
22485     {
22486         this.setPosition(new google.maps.LatLng(latitude, longitude));
22487     },
22488     
22489     getCurrentPosition: function() 
22490     {
22491         return {
22492             latitude: this.gMapContext.location.lat(),
22493             longitude: this.gMapContext.location.lng()
22494         };
22495     },
22496     
22497     getAddressName: function() 
22498     {
22499         return this.gMapContext.locationName;
22500     },
22501     
22502     getAddressComponents: function() 
22503     {
22504         return this.gMapContext.addressComponents;
22505     },
22506     
22507     address_component_from_google_geocode: function(address_components) 
22508     {
22509         var result = {};
22510         
22511         for (var i = 0; i < address_components.length; i++) {
22512             var component = address_components[i];
22513             if (component.types.indexOf("postal_code") >= 0) {
22514                 result.postalCode = component.short_name;
22515             } else if (component.types.indexOf("street_number") >= 0) {
22516                 result.streetNumber = component.short_name;
22517             } else if (component.types.indexOf("route") >= 0) {
22518                 result.streetName = component.short_name;
22519             } else if (component.types.indexOf("neighborhood") >= 0) {
22520                 result.city = component.short_name;
22521             } else if (component.types.indexOf("locality") >= 0) {
22522                 result.city = component.short_name;
22523             } else if (component.types.indexOf("sublocality") >= 0) {
22524                 result.district = component.short_name;
22525             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22526                 result.stateOrProvince = component.short_name;
22527             } else if (component.types.indexOf("country") >= 0) {
22528                 result.country = component.short_name;
22529             }
22530         }
22531         
22532         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22533         result.addressLine2 = "";
22534         return result;
22535     },
22536     
22537     setZoomLevel: function(zoom)
22538     {
22539         this.gMapContext.map.setZoom(zoom);
22540     },
22541     
22542     show: function()
22543     {
22544         if(!this.el){
22545             return;
22546         }
22547         
22548         this.el.show();
22549         
22550         this.resize();
22551         
22552         this.fireEvent('show', this);
22553     },
22554     
22555     hide: function()
22556     {
22557         if(!this.el){
22558             return;
22559         }
22560         
22561         this.el.hide();
22562         
22563         this.fireEvent('hide', this);
22564     }
22565     
22566 });
22567
22568 Roo.apply(Roo.bootstrap.LocationPicker, {
22569     
22570     OverlayView : function(map, options)
22571     {
22572         options = options || {};
22573         
22574         this.setMap(map);
22575     }
22576     
22577     
22578 });/*
22579  * - LGPL
22580  *
22581  * Alert
22582  * 
22583  */
22584
22585 /**
22586  * @class Roo.bootstrap.Alert
22587  * @extends Roo.bootstrap.Component
22588  * Bootstrap Alert class
22589  * @cfg {String} title The title of alert
22590  * @cfg {String} html The content of alert
22591  * @cfg {String} weight (  success | info | warning | danger )
22592  * @cfg {String} faicon font-awesomeicon
22593  * 
22594  * @constructor
22595  * Create a new alert
22596  * @param {Object} config The config object
22597  */
22598
22599
22600 Roo.bootstrap.Alert = function(config){
22601     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22602     
22603 };
22604
22605 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
22606     
22607     title: '',
22608     html: '',
22609     weight: false,
22610     faicon: false,
22611     
22612     getAutoCreate : function()
22613     {
22614         
22615         var cfg = {
22616             tag : 'div',
22617             cls : 'alert',
22618             cn : [
22619                 {
22620                     tag : 'i',
22621                     cls : 'roo-alert-icon'
22622                     
22623                 },
22624                 {
22625                     tag : 'b',
22626                     cls : 'roo-alert-title',
22627                     html : this.title
22628                 },
22629                 {
22630                     tag : 'span',
22631                     cls : 'roo-alert-text',
22632                     html : this.html
22633                 }
22634             ]
22635         };
22636         
22637         if(this.faicon){
22638             cfg.cn[0].cls += ' fa ' + this.faicon;
22639         }
22640         
22641         if(this.weight){
22642             cfg.cls += ' alert-' + this.weight;
22643         }
22644         
22645         return cfg;
22646     },
22647     
22648     initEvents: function() 
22649     {
22650         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22651     },
22652     
22653     setTitle : function(str)
22654     {
22655         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22656     },
22657     
22658     setText : function(str)
22659     {
22660         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22661     },
22662     
22663     setWeight : function(weight)
22664     {
22665         if(this.weight){
22666             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22667         }
22668         
22669         this.weight = weight;
22670         
22671         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22672     },
22673     
22674     setIcon : function(icon)
22675     {
22676         if(this.faicon){
22677             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22678         }
22679         
22680         this.faicon = icon
22681         
22682         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
22683     },
22684     
22685     hide: function() 
22686     {
22687         this.el.hide();   
22688     },
22689     
22690     show: function() 
22691     {  
22692         this.el.show();   
22693     }
22694     
22695 });
22696
22697