Roo/bootstrap/ComboBox.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.bootstrap.MenuItem} this
1975          * @param {Roo.EventObject} e
1976          */
1977         "click" : true
1978     });
1979 };
1980
1981 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
1982     
1983     href : false,
1984     html : false,
1985     preventDefault: true,
1986     isContainer : false,
1987     
1988     getAutoCreate : function(){
1989         
1990         if(this.isContainer){
1991             return {
1992                 tag: 'li',
1993                 cls: 'dropdown-menu-item'
1994             };
1995         }
1996         
1997         var cfg= {
1998             tag: 'li',
1999             cls: 'dropdown-menu-item',
2000             cn: [
2001                     {
2002                         tag : 'a',
2003                         href : '#',
2004                         html : 'Link'
2005                     }
2006                 ]
2007         };
2008         if (this.parent().type == 'treeview') {
2009             cfg.cls = 'treeview-menu';
2010         }
2011         
2012         cfg.cn[0].href = this.href || cfg.cn[0].href ;
2013         cfg.cn[0].html = this.html || cfg.cn[0].html ;
2014         return cfg;
2015     },
2016     
2017     initEvents: function() {
2018         
2019         //this.el.select('a').on('click', this.onClick, this);
2020         
2021     },
2022     onClick : function(e)
2023     {
2024         Roo.log('item on click ');
2025         //if(this.preventDefault){
2026         //    e.preventDefault();
2027         //}
2028         //this.parent().hideMenuItems();
2029         
2030         this.fireEvent('click', this, e);
2031     },
2032     getEl : function()
2033     {
2034         return this.el;
2035     }
2036 });
2037
2038  
2039
2040  /*
2041  * - LGPL
2042  *
2043  * menu separator
2044  * 
2045  */
2046
2047
2048 /**
2049  * @class Roo.bootstrap.MenuSeparator
2050  * @extends Roo.bootstrap.Component
2051  * Bootstrap MenuSeparator class
2052  * 
2053  * @constructor
2054  * Create a new MenuItem
2055  * @param {Object} config The config object
2056  */
2057
2058
2059 Roo.bootstrap.MenuSeparator = function(config){
2060     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2061 };
2062
2063 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2064     
2065     getAutoCreate : function(){
2066         var cfg = {
2067             cls: 'divider',
2068             tag : 'li'
2069         };
2070         
2071         return cfg;
2072     }
2073    
2074 });
2075
2076  
2077
2078  
2079 /*
2080 * Licence: LGPL
2081 */
2082
2083 /**
2084  * @class Roo.bootstrap.Modal
2085  * @extends Roo.bootstrap.Component
2086  * Bootstrap Modal class
2087  * @cfg {String} title Title of dialog
2088  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2089  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn 
2090  * @cfg {Boolean} specificTitle default false
2091  * @cfg {Array} buttons Array of buttons or standard button set..
2092  * @cfg {String} buttonPosition (left|right|center) default right
2093  * @cfg {Boolean} animate default true
2094  * @cfg {Boolean} allow_close default true
2095  * 
2096  * @constructor
2097  * Create a new Modal Dialog
2098  * @param {Object} config The config object
2099  */
2100
2101 Roo.bootstrap.Modal = function(config){
2102     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2103     this.addEvents({
2104         // raw events
2105         /**
2106          * @event btnclick
2107          * The raw btnclick event for the button
2108          * @param {Roo.EventObject} e
2109          */
2110         "btnclick" : true
2111     });
2112     this.buttons = this.buttons || [];
2113      
2114     if (this.tmpl) {
2115         this.tmpl = Roo.factory(this.tmpl);
2116     }
2117     
2118 };
2119
2120 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2121     
2122     title : 'test dialog',
2123    
2124     buttons : false,
2125     
2126     // set on load...
2127      
2128     html: false,
2129     
2130     tmp: false,
2131     
2132     specificTitle: false,
2133     
2134     buttonPosition: 'right',
2135     
2136     allow_close : true,
2137     
2138     animate : true,
2139     
2140     
2141      // private
2142     bodyEl:  false,
2143     footerEl:  false,
2144     titleEl:  false,
2145     closeEl:  false,
2146     
2147     
2148     onRender : function(ct, position)
2149     {
2150         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2151      
2152         if(!this.el){
2153             var cfg = Roo.apply({},  this.getAutoCreate());
2154             cfg.id = Roo.id();
2155             //if(!cfg.name){
2156             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2157             //}
2158             //if (!cfg.name.length) {
2159             //    delete cfg.name;
2160            // }
2161             if (this.cls) {
2162                 cfg.cls += ' ' + this.cls;
2163             }
2164             if (this.style) {
2165                 cfg.style = this.style;
2166             }
2167             this.el = Roo.get(document.body).createChild(cfg, position);
2168         }
2169         //var type = this.el.dom.type;
2170         
2171         
2172         
2173         
2174         if(this.tabIndex !== undefined){
2175             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2176         }
2177         
2178         
2179         this.bodyEl = this.el.select('.modal-body',true).first();
2180         this.closeEl = this.el.select('.modal-header .close', true).first();
2181         this.footerEl = this.el.select('.modal-footer',true).first();
2182         this.titleEl = this.el.select('.modal-title',true).first();
2183         
2184         
2185          
2186         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2187         this.maskEl.enableDisplayMode("block");
2188         this.maskEl.hide();
2189         //this.el.addClass("x-dlg-modal");
2190     
2191         if (this.buttons.length) {
2192             Roo.each(this.buttons, function(bb) {
2193                 b = Roo.apply({}, bb);
2194                 b.xns = b.xns || Roo.bootstrap;
2195                 b.xtype = b.xtype || 'Button';
2196                 if (typeof(b.listeners) == 'undefined') {
2197                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2198                 }
2199                 
2200                 var btn = Roo.factory(b);
2201                 
2202                 btn.onRender(this.el.select('.modal-footer div').first());
2203                 
2204             },this);
2205         }
2206         // render the children.
2207         var nitems = [];
2208         
2209         if(typeof(this.items) != 'undefined'){
2210             var items = this.items;
2211             delete this.items;
2212
2213             for(var i =0;i < items.length;i++) {
2214                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2215             }
2216         }
2217         
2218         this.items = nitems;
2219         
2220         // where are these used - they used to be body/close/footer
2221         
2222        
2223         this.initEvents();
2224         //this.el.addClass([this.fieldClass, this.cls]);
2225         
2226     },
2227     getAutoCreate : function(){
2228         
2229         
2230         var bdy = {
2231                 cls : 'modal-body',
2232                 html : this.html || ''
2233         };
2234         
2235         var title = {
2236             tag: 'h4',
2237             cls : 'modal-title',
2238             html : this.title
2239         };
2240         
2241         if(this.specificTitle){
2242             title = this.title;
2243             
2244         };
2245         
2246         var header = [];
2247         if (this.allow_close) {
2248             header.push({
2249                 tag: 'button',
2250                 cls : 'close',
2251                 html : '&times'
2252             });
2253         }
2254         header.push(title);
2255         
2256         var modal = {
2257             cls: "modal",
2258             style : 'display: none',
2259             cn : [
2260                 {
2261                     cls: "modal-dialog",
2262                     cn : [
2263                         {
2264                             cls : "modal-content",
2265                             cn : [
2266                                 {
2267                                     cls : 'modal-header',
2268                                     cn : header
2269                                 },
2270                                 bdy,
2271                                 {
2272                                     cls : 'modal-footer',
2273                                     cn : [
2274                                         {
2275                                             tag: 'div',
2276                                             cls: 'btn-' + this.buttonPosition
2277                                         }
2278                                     ]
2279                                     
2280                                 }
2281                                 
2282                                 
2283                             ]
2284                             
2285                         }
2286                     ]
2287                         
2288                 }
2289             ]
2290         };
2291         
2292         if(this.animate){
2293             modal.cls += ' fade';
2294         }
2295         
2296         return modal;
2297           
2298     },
2299     getChildContainer : function() {
2300          
2301          return this.bodyEl;
2302         
2303     },
2304     getButtonContainer : function() {
2305          return this.el.select('.modal-footer div',true).first();
2306         
2307     },
2308     initEvents : function()
2309     {
2310         if (this.allow_close) {
2311             this.closeEl.on('click', this.hide, this);
2312         }
2313
2314     },
2315     show : function() {
2316         
2317         if (!this.rendered) {
2318             this.render();
2319         }
2320         
2321         this.el.setStyle('display', 'block');
2322         
2323         if(this.animate){
2324             var _this = this;
2325             (function(){ _this.el.addClass('in'); }).defer(50);
2326         }else{
2327             this.el.addClass('in');
2328         }
2329         
2330         // not sure how we can show data in here.. 
2331         //if (this.tmpl) {
2332         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2333         //}
2334         
2335         Roo.get(document.body).addClass("x-body-masked");
2336         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2337         this.maskEl.show();
2338         this.el.setStyle('zIndex', '10001');
2339        
2340         this.fireEvent('show', this);
2341         
2342         
2343     },
2344     hide : function()
2345     {
2346         this.maskEl.hide();
2347         Roo.get(document.body).removeClass("x-body-masked");
2348         this.el.removeClass('in');
2349         
2350         if(this.animate){
2351             var _this = this;
2352             (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2353         }else{
2354             this.el.setStyle('display', 'none');
2355         }
2356         
2357         this.fireEvent('hide', this);
2358     },
2359     
2360     addButton : function(str, cb)
2361     {
2362          
2363         
2364         var b = Roo.apply({}, { html : str } );
2365         b.xns = b.xns || Roo.bootstrap;
2366         b.xtype = b.xtype || 'Button';
2367         if (typeof(b.listeners) == 'undefined') {
2368             b.listeners = { click : cb.createDelegate(this)  };
2369         }
2370         
2371         var btn = Roo.factory(b);
2372            
2373         btn.onRender(this.el.select('.modal-footer div').first());
2374         
2375         return btn;   
2376        
2377     },
2378     
2379     setDefaultButton : function(btn)
2380     {
2381         //this.el.select('.modal-footer').()
2382     },
2383     resizeTo: function(w,h)
2384     {
2385         // skip..
2386     },
2387     setContentSize  : function(w, h)
2388     {
2389         
2390     },
2391     onButtonClick: function(btn,e)
2392     {
2393         //Roo.log([a,b,c]);
2394         this.fireEvent('btnclick', btn.name, e);
2395     },
2396      /**
2397      * Set the title of the Dialog
2398      * @param {String} str new Title
2399      */
2400     setTitle: function(str) {
2401         this.titleEl.dom.innerHTML = str;    
2402     },
2403     /**
2404      * Set the body of the Dialog
2405      * @param {String} str new Title
2406      */
2407     setBody: function(str) {
2408         this.bodyEl.dom.innerHTML = str;    
2409     },
2410     /**
2411      * Set the body of the Dialog using the template
2412      * @param {Obj} data - apply this data to the template and replace the body contents.
2413      */
2414     applyBody: function(obj)
2415     {
2416         if (!this.tmpl) {
2417             Roo.log("Error - using apply Body without a template");
2418             //code
2419         }
2420         this.tmpl.overwrite(this.bodyEl, obj);
2421     }
2422     
2423 });
2424
2425
2426 Roo.apply(Roo.bootstrap.Modal,  {
2427     /**
2428          * Button config that displays a single OK button
2429          * @type Object
2430          */
2431         OK :  [{
2432             name : 'ok',
2433             weight : 'primary',
2434             html : 'OK'
2435         }], 
2436         /**
2437          * Button config that displays Yes and No buttons
2438          * @type Object
2439          */
2440         YESNO : [
2441             {
2442                 name  : 'no',
2443                 html : 'No'
2444             },
2445             {
2446                 name  :'yes',
2447                 weight : 'primary',
2448                 html : 'Yes'
2449             }
2450         ],
2451         
2452         /**
2453          * Button config that displays OK and Cancel buttons
2454          * @type Object
2455          */
2456         OKCANCEL : [
2457             {
2458                name : 'cancel',
2459                 html : 'Cancel'
2460             },
2461             {
2462                 name : 'ok',
2463                 weight : 'primary',
2464                 html : 'OK'
2465             }
2466         ],
2467         /**
2468          * Button config that displays Yes, No and Cancel buttons
2469          * @type Object
2470          */
2471         YESNOCANCEL : [
2472             {
2473                 name : 'yes',
2474                 weight : 'primary',
2475                 html : 'Yes'
2476             },
2477             {
2478                 name : 'no',
2479                 html : 'No'
2480             },
2481             {
2482                 name : 'cancel',
2483                 html : 'Cancel'
2484             }
2485         ]
2486 });
2487  
2488  /*
2489  * - LGPL
2490  *
2491  * messagebox - can be used as a replace
2492  * 
2493  */
2494 /**
2495  * @class Roo.MessageBox
2496  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
2497  * Example usage:
2498  *<pre><code>
2499 // Basic alert:
2500 Roo.Msg.alert('Status', 'Changes saved successfully.');
2501
2502 // Prompt for user data:
2503 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2504     if (btn == 'ok'){
2505         // process text value...
2506     }
2507 });
2508
2509 // Show a dialog using config options:
2510 Roo.Msg.show({
2511    title:'Save Changes?',
2512    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2513    buttons: Roo.Msg.YESNOCANCEL,
2514    fn: processResult,
2515    animEl: 'elId'
2516 });
2517 </code></pre>
2518  * @singleton
2519  */
2520 Roo.bootstrap.MessageBox = function(){
2521     var dlg, opt, mask, waitTimer;
2522     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2523     var buttons, activeTextEl, bwidth;
2524
2525     
2526     // private
2527     var handleButton = function(button){
2528         dlg.hide();
2529         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2530     };
2531
2532     // private
2533     var handleHide = function(){
2534         if(opt && opt.cls){
2535             dlg.el.removeClass(opt.cls);
2536         }
2537         //if(waitTimer){
2538         //    Roo.TaskMgr.stop(waitTimer);
2539         //    waitTimer = null;
2540         //}
2541     };
2542
2543     // private
2544     var updateButtons = function(b){
2545         var width = 0;
2546         if(!b){
2547             buttons["ok"].hide();
2548             buttons["cancel"].hide();
2549             buttons["yes"].hide();
2550             buttons["no"].hide();
2551             //dlg.footer.dom.style.display = 'none';
2552             return width;
2553         }
2554         dlg.footerEl.dom.style.display = '';
2555         for(var k in buttons){
2556             if(typeof buttons[k] != "function"){
2557                 if(b[k]){
2558                     buttons[k].show();
2559                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2560                     width += buttons[k].el.getWidth()+15;
2561                 }else{
2562                     buttons[k].hide();
2563                 }
2564             }
2565         }
2566         return width;
2567     };
2568
2569     // private
2570     var handleEsc = function(d, k, e){
2571         if(opt && opt.closable !== false){
2572             dlg.hide();
2573         }
2574         if(e){
2575             e.stopEvent();
2576         }
2577     };
2578
2579     return {
2580         /**
2581          * Returns a reference to the underlying {@link Roo.BasicDialog} element
2582          * @return {Roo.BasicDialog} The BasicDialog element
2583          */
2584         getDialog : function(){
2585            if(!dlg){
2586                 dlg = new Roo.bootstrap.Modal( {
2587                     //draggable: true,
2588                     //resizable:false,
2589                     //constraintoviewport:false,
2590                     //fixedcenter:true,
2591                     //collapsible : false,
2592                     //shim:true,
2593                     //modal: true,
2594                   //  width:400,
2595                   //  height:100,
2596                     //buttonAlign:"center",
2597                     closeClick : function(){
2598                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2599                             handleButton("no");
2600                         }else{
2601                             handleButton("cancel");
2602                         }
2603                     }
2604                 });
2605                 dlg.render();
2606                 dlg.on("hide", handleHide);
2607                 mask = dlg.mask;
2608                 //dlg.addKeyListener(27, handleEsc);
2609                 buttons = {};
2610                 this.buttons = buttons;
2611                 var bt = this.buttonText;
2612                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2613                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2614                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2615                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2616                 Roo.log(buttons)
2617                 bodyEl = dlg.bodyEl.createChild({
2618
2619                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2620                         '<textarea class="roo-mb-textarea"></textarea>' +
2621                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
2622                 });
2623                 msgEl = bodyEl.dom.firstChild;
2624                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2625                 textboxEl.enableDisplayMode();
2626                 textboxEl.addKeyListener([10,13], function(){
2627                     if(dlg.isVisible() && opt && opt.buttons){
2628                         if(opt.buttons.ok){
2629                             handleButton("ok");
2630                         }else if(opt.buttons.yes){
2631                             handleButton("yes");
2632                         }
2633                     }
2634                 });
2635                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2636                 textareaEl.enableDisplayMode();
2637                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2638                 progressEl.enableDisplayMode();
2639                 var pf = progressEl.dom.firstChild;
2640                 if (pf) {
2641                     pp = Roo.get(pf.firstChild);
2642                     pp.setHeight(pf.offsetHeight);
2643                 }
2644                 
2645             }
2646             return dlg;
2647         },
2648
2649         /**
2650          * Updates the message box body text
2651          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2652          * the XHTML-compliant non-breaking space character '&amp;#160;')
2653          * @return {Roo.MessageBox} This message box
2654          */
2655         updateText : function(text){
2656             if(!dlg.isVisible() && !opt.width){
2657                 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2658             }
2659             msgEl.innerHTML = text || '&#160;';
2660       
2661             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2662             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2663             var w = Math.max(
2664                     Math.min(opt.width || cw , this.maxWidth), 
2665                     Math.max(opt.minWidth || this.minWidth, bwidth)
2666             );
2667             if(opt.prompt){
2668                 activeTextEl.setWidth(w);
2669             }
2670             if(dlg.isVisible()){
2671                 dlg.fixedcenter = false;
2672             }
2673             // to big, make it scroll. = But as usual stupid IE does not support
2674             // !important..
2675             
2676             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2677                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2678                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2679             } else {
2680                 bodyEl.dom.style.height = '';
2681                 bodyEl.dom.style.overflowY = '';
2682             }
2683             if (cw > w) {
2684                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2685             } else {
2686                 bodyEl.dom.style.overflowX = '';
2687             }
2688             
2689             dlg.setContentSize(w, bodyEl.getHeight());
2690             if(dlg.isVisible()){
2691                 dlg.fixedcenter = true;
2692             }
2693             return this;
2694         },
2695
2696         /**
2697          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
2698          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2699          * @param {Number} value Any number between 0 and 1 (e.g., .5)
2700          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2701          * @return {Roo.MessageBox} This message box
2702          */
2703         updateProgress : function(value, text){
2704             if(text){
2705                 this.updateText(text);
2706             }
2707             if (pp) { // weird bug on my firefox - for some reason this is not defined
2708                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2709             }
2710             return this;
2711         },        
2712
2713         /**
2714          * Returns true if the message box is currently displayed
2715          * @return {Boolean} True if the message box is visible, else false
2716          */
2717         isVisible : function(){
2718             return dlg && dlg.isVisible();  
2719         },
2720
2721         /**
2722          * Hides the message box if it is displayed
2723          */
2724         hide : function(){
2725             if(this.isVisible()){
2726                 dlg.hide();
2727             }  
2728         },
2729
2730         /**
2731          * Displays a new message box, or reinitializes an existing message box, based on the config options
2732          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2733          * The following config object properties are supported:
2734          * <pre>
2735 Property    Type             Description
2736 ----------  ---------------  ------------------------------------------------------------------------------------
2737 animEl            String/Element   An id or Element from which the message box should animate as it opens and
2738                                    closes (defaults to undefined)
2739 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2740                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
2741 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
2742                                    progress and wait dialogs will ignore this property and always hide the
2743                                    close button as they can only be closed programmatically.
2744 cls               String           A custom CSS class to apply to the message box element
2745 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
2746                                    displayed (defaults to 75)
2747 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
2748                                    function will be btn (the name of the button that was clicked, if applicable,
2749                                    e.g. "ok"), and text (the value of the active text field, if applicable).
2750                                    Progress and wait dialogs will ignore this option since they do not respond to
2751                                    user actions and can only be closed programmatically, so any required function
2752                                    should be called by the same code after it closes the dialog.
2753 icon              String           A CSS class that provides a background image to be used as an icon for
2754                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2755 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
2756 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
2757 modal             Boolean          False to allow user interaction with the page while the message box is
2758                                    displayed (defaults to true)
2759 msg               String           A string that will replace the existing message box body text (defaults
2760                                    to the XHTML-compliant non-breaking space character '&#160;')
2761 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
2762 progress          Boolean          True to display a progress bar (defaults to false)
2763 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
2764 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
2765 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
2766 title             String           The title text
2767 value             String           The string value to set into the active textbox element if displayed
2768 wait              Boolean          True to display a progress bar (defaults to false)
2769 width             Number           The width of the dialog in pixels
2770 </pre>
2771          *
2772          * Example usage:
2773          * <pre><code>
2774 Roo.Msg.show({
2775    title: 'Address',
2776    msg: 'Please enter your address:',
2777    width: 300,
2778    buttons: Roo.MessageBox.OKCANCEL,
2779    multiline: true,
2780    fn: saveAddress,
2781    animEl: 'addAddressBtn'
2782 });
2783 </code></pre>
2784          * @param {Object} config Configuration options
2785          * @return {Roo.MessageBox} This message box
2786          */
2787         show : function(options)
2788         {
2789             
2790             // this causes nightmares if you show one dialog after another
2791             // especially on callbacks..
2792              
2793             if(this.isVisible()){
2794                 
2795                 this.hide();
2796                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2797                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
2798                 Roo.log("New Dialog Message:" +  options.msg )
2799                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2800                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2801                 
2802             }
2803             var d = this.getDialog();
2804             opt = options;
2805             d.setTitle(opt.title || "&#160;");
2806             d.closeEl.setDisplayed(opt.closable !== false);
2807             activeTextEl = textboxEl;
2808             opt.prompt = opt.prompt || (opt.multiline ? true : false);
2809             if(opt.prompt){
2810                 if(opt.multiline){
2811                     textboxEl.hide();
2812                     textareaEl.show();
2813                     textareaEl.setHeight(typeof opt.multiline == "number" ?
2814                         opt.multiline : this.defaultTextHeight);
2815                     activeTextEl = textareaEl;
2816                 }else{
2817                     textboxEl.show();
2818                     textareaEl.hide();
2819                 }
2820             }else{
2821                 textboxEl.hide();
2822                 textareaEl.hide();
2823             }
2824             progressEl.setDisplayed(opt.progress === true);
2825             this.updateProgress(0);
2826             activeTextEl.dom.value = opt.value || "";
2827             if(opt.prompt){
2828                 dlg.setDefaultButton(activeTextEl);
2829             }else{
2830                 var bs = opt.buttons;
2831                 var db = null;
2832                 if(bs && bs.ok){
2833                     db = buttons["ok"];
2834                 }else if(bs && bs.yes){
2835                     db = buttons["yes"];
2836                 }
2837                 dlg.setDefaultButton(db);
2838             }
2839             bwidth = updateButtons(opt.buttons);
2840             this.updateText(opt.msg);
2841             if(opt.cls){
2842                 d.el.addClass(opt.cls);
2843             }
2844             d.proxyDrag = opt.proxyDrag === true;
2845             d.modal = opt.modal !== false;
2846             d.mask = opt.modal !== false ? mask : false;
2847             if(!d.isVisible()){
2848                 // force it to the end of the z-index stack so it gets a cursor in FF
2849                 document.body.appendChild(dlg.el.dom);
2850                 d.animateTarget = null;
2851                 d.show(options.animEl);
2852             }
2853             return this;
2854         },
2855
2856         /**
2857          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
2858          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2859          * and closing the message box when the process is complete.
2860          * @param {String} title The title bar text
2861          * @param {String} msg The message box body text
2862          * @return {Roo.MessageBox} This message box
2863          */
2864         progress : function(title, msg){
2865             this.show({
2866                 title : title,
2867                 msg : msg,
2868                 buttons: false,
2869                 progress:true,
2870                 closable:false,
2871                 minWidth: this.minProgressWidth,
2872                 modal : true
2873             });
2874             return this;
2875         },
2876
2877         /**
2878          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2879          * If a callback function is passed it will be called after the user clicks the button, and the
2880          * id of the button that was clicked will be passed as the only parameter to the callback
2881          * (could also be the top-right close button).
2882          * @param {String} title The title bar text
2883          * @param {String} msg The message box body text
2884          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2885          * @param {Object} scope (optional) The scope of the callback function
2886          * @return {Roo.MessageBox} This message box
2887          */
2888         alert : function(title, msg, fn, scope){
2889             this.show({
2890                 title : title,
2891                 msg : msg,
2892                 buttons: this.OK,
2893                 fn: fn,
2894                 scope : scope,
2895                 modal : true
2896             });
2897             return this;
2898         },
2899
2900         /**
2901          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
2902          * interaction while waiting for a long-running process to complete that does not have defined intervals.
2903          * You are responsible for closing the message box when the process is complete.
2904          * @param {String} msg The message box body text
2905          * @param {String} title (optional) The title bar text
2906          * @return {Roo.MessageBox} This message box
2907          */
2908         wait : function(msg, title){
2909             this.show({
2910                 title : title,
2911                 msg : msg,
2912                 buttons: false,
2913                 closable:false,
2914                 progress:true,
2915                 modal:true,
2916                 width:300,
2917                 wait:true
2918             });
2919             waitTimer = Roo.TaskMgr.start({
2920                 run: function(i){
2921                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2922                 },
2923                 interval: 1000
2924             });
2925             return this;
2926         },
2927
2928         /**
2929          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2930          * If a callback function is passed it will be called after the user clicks either button, and the id of the
2931          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2932          * @param {String} title The title bar text
2933          * @param {String} msg The message box body text
2934          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2935          * @param {Object} scope (optional) The scope of the callback function
2936          * @return {Roo.MessageBox} This message box
2937          */
2938         confirm : function(title, msg, fn, scope){
2939             this.show({
2940                 title : title,
2941                 msg : msg,
2942                 buttons: this.YESNO,
2943                 fn: fn,
2944                 scope : scope,
2945                 modal : true
2946             });
2947             return this;
2948         },
2949
2950         /**
2951          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2952          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
2953          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2954          * (could also be the top-right close button) and the text that was entered will be passed as the two
2955          * parameters to the callback.
2956          * @param {String} title The title bar text
2957          * @param {String} msg The message box body text
2958          * @param {Function} fn (optional) The callback function invoked after the message box is closed
2959          * @param {Object} scope (optional) The scope of the callback function
2960          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2961          * property, or the height in pixels to create the textbox (defaults to false / single-line)
2962          * @return {Roo.MessageBox} This message box
2963          */
2964         prompt : function(title, msg, fn, scope, multiline){
2965             this.show({
2966                 title : title,
2967                 msg : msg,
2968                 buttons: this.OKCANCEL,
2969                 fn: fn,
2970                 minWidth:250,
2971                 scope : scope,
2972                 prompt:true,
2973                 multiline: multiline,
2974                 modal : true
2975             });
2976             return this;
2977         },
2978
2979         /**
2980          * Button config that displays a single OK button
2981          * @type Object
2982          */
2983         OK : {ok:true},
2984         /**
2985          * Button config that displays Yes and No buttons
2986          * @type Object
2987          */
2988         YESNO : {yes:true, no:true},
2989         /**
2990          * Button config that displays OK and Cancel buttons
2991          * @type Object
2992          */
2993         OKCANCEL : {ok:true, cancel:true},
2994         /**
2995          * Button config that displays Yes, No and Cancel buttons
2996          * @type Object
2997          */
2998         YESNOCANCEL : {yes:true, no:true, cancel:true},
2999
3000         /**
3001          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3002          * @type Number
3003          */
3004         defaultTextHeight : 75,
3005         /**
3006          * The maximum width in pixels of the message box (defaults to 600)
3007          * @type Number
3008          */
3009         maxWidth : 600,
3010         /**
3011          * The minimum width in pixels of the message box (defaults to 100)
3012          * @type Number
3013          */
3014         minWidth : 100,
3015         /**
3016          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3017          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3018          * @type Number
3019          */
3020         minProgressWidth : 250,
3021         /**
3022          * An object containing the default button text strings that can be overriden for localized language support.
3023          * Supported properties are: ok, cancel, yes and no.
3024          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3025          * @type Object
3026          */
3027         buttonText : {
3028             ok : "OK",
3029             cancel : "Cancel",
3030             yes : "Yes",
3031             no : "No"
3032         }
3033     };
3034 }();
3035
3036 /**
3037  * Shorthand for {@link Roo.MessageBox}
3038  */
3039 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3040 Roo.Msg = Roo.Msg || Roo.MessageBox;
3041 /*
3042  * - LGPL
3043  *
3044  * navbar
3045  * 
3046  */
3047
3048 /**
3049  * @class Roo.bootstrap.Navbar
3050  * @extends Roo.bootstrap.Component
3051  * Bootstrap Navbar class
3052
3053  * @constructor
3054  * Create a new Navbar
3055  * @param {Object} config The config object
3056  */
3057
3058
3059 Roo.bootstrap.Navbar = function(config){
3060     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3061     
3062 };
3063
3064 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3065     
3066     
3067    
3068     // private
3069     navItems : false,
3070     loadMask : false,
3071     
3072     
3073     getAutoCreate : function(){
3074         
3075         
3076         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3077         
3078     },
3079     
3080     initEvents :function ()
3081     {
3082         //Roo.log(this.el.select('.navbar-toggle',true));
3083         this.el.select('.navbar-toggle',true).on('click', function() {
3084            // Roo.log('click');
3085             this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3086         }, this);
3087         
3088         var mark = {
3089             tag: "div",
3090             cls:"x-dlg-mask"
3091         }
3092         
3093         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3094         
3095         var size = this.el.getSize();
3096         this.maskEl.setSize(size.width, size.height);
3097         this.maskEl.enableDisplayMode("block");
3098         this.maskEl.hide();
3099         
3100         if(this.loadMask){
3101             this.maskEl.show();
3102         }
3103     },
3104     
3105     
3106     getChildContainer : function()
3107     {
3108         if (this.el.select('.collapse').getCount()) {
3109             return this.el.select('.collapse',true).first();
3110         }
3111         
3112         return this.el;
3113     },
3114     
3115     mask : function()
3116     {
3117         this.maskEl.show();
3118     },
3119     
3120     unmask : function()
3121     {
3122         this.maskEl.hide();
3123     } 
3124     
3125     
3126     
3127     
3128 });
3129
3130
3131
3132  
3133
3134  /*
3135  * - LGPL
3136  *
3137  * navbar
3138  * 
3139  */
3140
3141 /**
3142  * @class Roo.bootstrap.NavSimplebar
3143  * @extends Roo.bootstrap.Navbar
3144  * Bootstrap Sidebar class
3145  *
3146  * @cfg {Boolean} inverse is inverted color
3147  * 
3148  * @cfg {String} type (nav | pills | tabs)
3149  * @cfg {Boolean} arrangement stacked | justified
3150  * @cfg {String} align (left | right) alignment
3151  * 
3152  * @cfg {Boolean} main (true|false) main nav bar? default false
3153  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3154  * 
3155  * @cfg {String} tag (header|footer|nav|div) default is nav 
3156
3157  * 
3158  * 
3159  * 
3160  * @constructor
3161  * Create a new Sidebar
3162  * @param {Object} config The config object
3163  */
3164
3165
3166 Roo.bootstrap.NavSimplebar = function(config){
3167     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3168 };
3169
3170 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3171     
3172     inverse: false,
3173     
3174     type: false,
3175     arrangement: '',
3176     align : false,
3177     
3178     
3179     
3180     main : false,
3181     
3182     
3183     tag : false,
3184     
3185     
3186     getAutoCreate : function(){
3187         
3188         
3189         var cfg = {
3190             tag : this.tag || 'div',
3191             cls : 'navbar'
3192         };
3193           
3194         
3195         cfg.cn = [
3196             {
3197                 cls: 'nav',
3198                 tag : 'ul'
3199             }
3200         ];
3201         
3202          
3203         this.type = this.type || 'nav';
3204         if (['tabs','pills'].indexOf(this.type)!==-1) {
3205             cfg.cn[0].cls += ' nav-' + this.type
3206         
3207         
3208         } else {
3209             if (this.type!=='nav') {
3210                 Roo.log('nav type must be nav/tabs/pills')
3211             }
3212             cfg.cn[0].cls += ' navbar-nav'
3213         }
3214         
3215         
3216         
3217         
3218         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3219             cfg.cn[0].cls += ' nav-' + this.arrangement;
3220         }
3221         
3222         
3223         if (this.align === 'right') {
3224             cfg.cn[0].cls += ' navbar-right';
3225         }
3226         
3227         if (this.inverse) {
3228             cfg.cls += ' navbar-inverse';
3229             
3230         }
3231         
3232         
3233         return cfg;
3234     
3235         
3236     }
3237     
3238     
3239     
3240 });
3241
3242
3243
3244  
3245
3246  
3247        /*
3248  * - LGPL
3249  *
3250  * navbar
3251  * 
3252  */
3253
3254 /**
3255  * @class Roo.bootstrap.NavHeaderbar
3256  * @extends Roo.bootstrap.NavSimplebar
3257  * Bootstrap Sidebar class
3258  *
3259  * @cfg {String} brand what is brand
3260  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3261  * @cfg {String} brand_href href of the brand
3262  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3263  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3264  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3265  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3266  * 
3267  * @constructor
3268  * Create a new Sidebar
3269  * @param {Object} config The config object
3270  */
3271
3272
3273 Roo.bootstrap.NavHeaderbar = function(config){
3274     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3275       
3276 };
3277
3278 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3279     
3280     position: '',
3281     brand: '',
3282     brand_href: false,
3283     srButton : true,
3284     autohide : false,
3285     desktopCenter : false,
3286    
3287     
3288     getAutoCreate : function(){
3289         
3290         var   cfg = {
3291             tag: this.nav || 'nav',
3292             cls: 'navbar',
3293             role: 'navigation',
3294             cn: []
3295         };
3296         
3297         var cn = cfg.cn;
3298         if (this.desktopCenter) {
3299             cn.push({cls : 'container', cn : []});
3300             cn = cn[0].cn;
3301         }
3302         
3303         if(this.srButton){
3304             cn.push({
3305                 tag: 'div',
3306                 cls: 'navbar-header',
3307                 cn: [
3308                     {
3309                         tag: 'button',
3310                         type: 'button',
3311                         cls: 'navbar-toggle',
3312                         'data-toggle': 'collapse',
3313                         cn: [
3314                             {
3315                                 tag: 'span',
3316                                 cls: 'sr-only',
3317                                 html: 'Toggle navigation'
3318                             },
3319                             {
3320                                 tag: 'span',
3321                                 cls: 'icon-bar'
3322                             },
3323                             {
3324                                 tag: 'span',
3325                                 cls: 'icon-bar'
3326                             },
3327                             {
3328                                 tag: 'span',
3329                                 cls: 'icon-bar'
3330                             }
3331                         ]
3332                     }
3333                 ]
3334             });
3335         }
3336         
3337         cn.push({
3338             tag: 'div',
3339             cls: 'collapse navbar-collapse',
3340             cn : []
3341         });
3342         
3343         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3344         
3345         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3346             cfg.cls += ' navbar-' + this.position;
3347             
3348             // tag can override this..
3349             
3350             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3351         }
3352         
3353         if (this.brand !== '') {
3354             cn[0].cn.push({
3355                 tag: 'a',
3356                 href: this.brand_href ? this.brand_href : '#',
3357                 cls: 'navbar-brand',
3358                 cn: [
3359                 this.brand
3360                 ]
3361             });
3362         }
3363         
3364         if(this.main){
3365             cfg.cls += ' main-nav';
3366         }
3367         
3368         
3369         return cfg;
3370
3371         
3372     },
3373     getHeaderChildContainer : function()
3374     {
3375         if (this.el.select('.navbar-header').getCount()) {
3376             return this.el.select('.navbar-header',true).first();
3377         }
3378         
3379         return this.getChildContainer();
3380     },
3381     
3382     
3383     initEvents : function()
3384     {
3385         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3386         
3387         if (this.autohide) {
3388             
3389             var prevScroll = 0;
3390             var ft = this.el;
3391             
3392             Roo.get(document).on('scroll',function(e) {
3393                 var ns = Roo.get(document).getScroll().top;
3394                 var os = prevScroll;
3395                 prevScroll = ns;
3396                 
3397                 if(ns > os){
3398                     ft.removeClass('slideDown');
3399                     ft.addClass('slideUp');
3400                     return;
3401                 }
3402                 ft.removeClass('slideUp');
3403                 ft.addClass('slideDown');
3404                  
3405               
3406           },this);
3407         }
3408     }    
3409           
3410       
3411     
3412     
3413 });
3414
3415
3416
3417  
3418
3419  /*
3420  * - LGPL
3421  *
3422  * navbar
3423  * 
3424  */
3425
3426 /**
3427  * @class Roo.bootstrap.NavSidebar
3428  * @extends Roo.bootstrap.Navbar
3429  * Bootstrap Sidebar class
3430  * 
3431  * @constructor
3432  * Create a new Sidebar
3433  * @param {Object} config The config object
3434  */
3435
3436
3437 Roo.bootstrap.NavSidebar = function(config){
3438     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3439 };
3440
3441 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
3442     
3443     sidebar : true, // used by Navbar Item and NavbarGroup at present...
3444     
3445     getAutoCreate : function(){
3446         
3447         
3448         return  {
3449             tag: 'div',
3450             cls: 'sidebar sidebar-nav'
3451         };
3452     
3453         
3454     }
3455     
3456     
3457     
3458 });
3459
3460
3461
3462  
3463
3464  /*
3465  * - LGPL
3466  *
3467  * nav group
3468  * 
3469  */
3470
3471 /**
3472  * @class Roo.bootstrap.NavGroup
3473  * @extends Roo.bootstrap.Component
3474  * Bootstrap NavGroup class
3475  * @cfg {String} align left | right
3476  * @cfg {Boolean} inverse false | true
3477  * @cfg {String} type (nav|pills|tab) default nav
3478  * @cfg {String} navId - reference Id for navbar.
3479
3480  * 
3481  * @constructor
3482  * Create a new nav group
3483  * @param {Object} config The config object
3484  */
3485
3486 Roo.bootstrap.NavGroup = function(config){
3487     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3488     this.navItems = [];
3489    
3490     Roo.bootstrap.NavGroup.register(this);
3491      this.addEvents({
3492         /**
3493              * @event changed
3494              * Fires when the active item changes
3495              * @param {Roo.bootstrap.NavGroup} this
3496              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3497              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
3498          */
3499         'changed': true
3500      });
3501     
3502 };
3503
3504 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
3505     
3506     align: '',
3507     inverse: false,
3508     form: false,
3509     type: 'nav',
3510     navId : '',
3511     // private
3512     
3513     navItems : false, 
3514     
3515     getAutoCreate : function()
3516     {
3517         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3518         
3519         cfg = {
3520             tag : 'ul',
3521             cls: 'nav' 
3522         }
3523         
3524         if (['tabs','pills'].indexOf(this.type)!==-1) {
3525             cfg.cls += ' nav-' + this.type
3526         } else {
3527             if (this.type!=='nav') {
3528                 Roo.log('nav type must be nav/tabs/pills')
3529             }
3530             cfg.cls += ' navbar-nav'
3531         }
3532         
3533         if (this.parent().sidebar) {
3534             cfg = {
3535                 tag: 'ul',
3536                 cls: 'dashboard-menu sidebar-menu'
3537             }
3538             
3539             return cfg;
3540         }
3541         
3542         if (this.form === true) {
3543             cfg = {
3544                 tag: 'form',
3545                 cls: 'navbar-form'
3546             }
3547             
3548             if (this.align === 'right') {
3549                 cfg.cls += ' navbar-right';
3550             } else {
3551                 cfg.cls += ' navbar-left';
3552             }
3553         }
3554         
3555         if (this.align === 'right') {
3556             cfg.cls += ' navbar-right';
3557         }
3558         
3559         if (this.inverse) {
3560             cfg.cls += ' navbar-inverse';
3561             
3562         }
3563         
3564         
3565         return cfg;
3566     },
3567     /**
3568     * sets the active Navigation item
3569     * @param {Roo.bootstrap.NavItem} the new current navitem
3570     */
3571     setActiveItem : function(item)
3572     {
3573         var prev = false;
3574         Roo.each(this.navItems, function(v){
3575             if (v == item) {
3576                 return ;
3577             }
3578             if (v.isActive()) {
3579                 v.setActive(false, true);
3580                 prev = v;
3581                 
3582             }
3583             
3584         });
3585
3586         item.setActive(true, true);
3587         this.fireEvent('changed', this, item, prev);
3588         
3589         
3590     },
3591     /**
3592     * gets the active Navigation item
3593     * @return {Roo.bootstrap.NavItem} the current navitem
3594     */
3595     getActive : function()
3596     {
3597         
3598         var prev = false;
3599         Roo.each(this.navItems, function(v){
3600             
3601             if (v.isActive()) {
3602                 prev = v;
3603                 
3604             }
3605             
3606         });
3607         return prev;
3608     },
3609     
3610     indexOfNav : function()
3611     {
3612         
3613         var prev = false;
3614         Roo.each(this.navItems, function(v,i){
3615             
3616             if (v.isActive()) {
3617                 prev = i;
3618                 
3619             }
3620             
3621         });
3622         return prev;
3623     },
3624     /**
3625     * adds a Navigation item
3626     * @param {Roo.bootstrap.NavItem} the navitem to add
3627     */
3628     addItem : function(cfg)
3629     {
3630         var cn = new Roo.bootstrap.NavItem(cfg);
3631         this.register(cn);
3632         cn.parentId = this.id;
3633         cn.onRender(this.el, null);
3634         return cn;
3635     },
3636     /**
3637     * register a Navigation item
3638     * @param {Roo.bootstrap.NavItem} the navitem to add
3639     */
3640     register : function(item)
3641     {
3642         this.navItems.push( item);
3643         item.navId = this.navId;
3644     
3645     },
3646     
3647     /**
3648     * clear all the Navigation item
3649     */
3650    
3651     clearAll : function()
3652     {
3653         this.navItems = [];
3654         this.el.dom.innerHTML = '';
3655     },
3656     
3657     getNavItem: function(tabId)
3658     {
3659         var ret = false;
3660         Roo.each(this.navItems, function(e) {
3661             if (e.tabId == tabId) {
3662                ret =  e;
3663                return false;
3664             }
3665             return true;
3666             
3667         });
3668         return ret;
3669     },
3670     
3671     setActiveNext : function()
3672     {
3673         var i = this.indexOfNav(this.getActive());
3674         if (i > this.navItems.length) {
3675             return;
3676         }
3677         this.setActiveItem(this.navItems[i+1]);
3678     },
3679     setActivePrev : function()
3680     {
3681         var i = this.indexOfNav(this.getActive());
3682         if (i  < 1) {
3683             return;
3684         }
3685         this.setActiveItem(this.navItems[i-1]);
3686     },
3687     clearWasActive : function(except) {
3688         Roo.each(this.navItems, function(e) {
3689             if (e.tabId != except.tabId && e.was_active) {
3690                e.was_active = false;
3691                return false;
3692             }
3693             return true;
3694             
3695         });
3696     },
3697     getWasActive : function ()
3698     {
3699         var r = false;
3700         Roo.each(this.navItems, function(e) {
3701             if (e.was_active) {
3702                r = e;
3703                return false;
3704             }
3705             return true;
3706             
3707         });
3708         return r;
3709     }
3710     
3711     
3712 });
3713
3714  
3715 Roo.apply(Roo.bootstrap.NavGroup, {
3716     
3717     groups: {},
3718      /**
3719     * register a Navigation Group
3720     * @param {Roo.bootstrap.NavGroup} the navgroup to add
3721     */
3722     register : function(navgrp)
3723     {
3724         this.groups[navgrp.navId] = navgrp;
3725         
3726     },
3727     /**
3728     * fetch a Navigation Group based on the navigation ID
3729     * @param {string} the navgroup to add
3730     * @returns {Roo.bootstrap.NavGroup} the navgroup 
3731     */
3732     get: function(navId) {
3733         if (typeof(this.groups[navId]) == 'undefined') {
3734             return false;
3735             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3736         }
3737         return this.groups[navId] ;
3738     }
3739     
3740     
3741     
3742 });
3743
3744  /*
3745  * - LGPL
3746  *
3747  * row
3748  * 
3749  */
3750
3751 /**
3752  * @class Roo.bootstrap.NavItem
3753  * @extends Roo.bootstrap.Component
3754  * Bootstrap Navbar.NavItem class
3755  * @cfg {String} href  link to
3756  * @cfg {String} html content of button
3757  * @cfg {String} badge text inside badge
3758  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3759  * @cfg {String} glyphicon name of glyphicon
3760  * @cfg {String} icon name of font awesome icon
3761  * @cfg {Boolean} active Is item active
3762  * @cfg {Boolean} disabled Is item disabled
3763  
3764  * @cfg {Boolean} preventDefault (true | false) default false
3765  * @cfg {String} tabId the tab that this item activates.
3766  * @cfg {String} tagtype (a|span) render as a href or span?
3767  * @cfg {Boolean} animateRef (true|false) link to element default false
3768   
3769  * @constructor
3770  * Create a new Navbar Item
3771  * @param {Object} config The config object
3772  */
3773 Roo.bootstrap.NavItem = function(config){
3774     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3775     this.addEvents({
3776         // raw events
3777         /**
3778          * @event click
3779          * The raw click event for the entire grid.
3780          * @param {Roo.EventObject} e
3781          */
3782         "click" : true,
3783          /**
3784             * @event changed
3785             * Fires when the active item active state changes
3786             * @param {Roo.bootstrap.NavItem} this
3787             * @param {boolean} state the new state
3788              
3789          */
3790         'changed': true,
3791         /**
3792             * @event scrollto
3793             * Fires when scroll to element
3794             * @param {Roo.bootstrap.NavItem} this
3795             * @param {Object} options
3796             * @param {Roo.EventObject} e
3797              
3798          */
3799         'scrollto': true
3800     });
3801    
3802 };
3803
3804 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
3805     
3806     href: false,
3807     html: '',
3808     badge: '',
3809     icon: false,
3810     glyphicon: false,
3811     active: false,
3812     preventDefault : false,
3813     tabId : false,
3814     tagtype : 'a',
3815     disabled : false,
3816     animateRef : false,
3817     was_active : false,
3818     
3819     getAutoCreate : function(){
3820          
3821         var cfg = {
3822             tag: 'li',
3823             cls: 'nav-item'
3824             
3825         }
3826         if (this.active) {
3827             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3828         }
3829         if (this.disabled) {
3830             cfg.cls += ' disabled';
3831         }
3832         
3833         if (this.href || this.html || this.glyphicon || this.icon) {
3834             cfg.cn = [
3835                 {
3836                     tag: this.tagtype,
3837                     href : this.href || "#",
3838                     html: this.html || ''
3839                 }
3840             ];
3841             
3842             if (this.icon) {
3843                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3844             }
3845
3846             if(this.glyphicon) {
3847                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
3848             }
3849             
3850             if (this.menu) {
3851                 
3852                 cfg.cn[0].html += " <span class='caret'></span>";
3853              
3854             }
3855             
3856             if (this.badge !== '') {
3857                  
3858                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3859             }
3860         }
3861         
3862         
3863         
3864         return cfg;
3865     },
3866     initEvents: function() 
3867     {
3868         if (typeof (this.menu) != 'undefined') {
3869             this.menu.parentType = this.xtype;
3870             this.menu.triggerEl = this.el;
3871             this.menu = this.addxtype(Roo.apply({}, this.menu));
3872         }
3873         
3874         this.el.select('a',true).on('click', this.onClick, this);
3875         
3876         if(this.tagtype == 'span'){
3877             this.el.select('span',true).on('click', this.onClick, this);
3878         }
3879        
3880         // at this point parent should be available..
3881         this.parent().register(this);
3882     },
3883     
3884     onClick : function(e)
3885     {
3886         if(
3887                 this.preventDefault || 
3888                 this.href == '#' ||
3889                 (this.animateRef && this.href.charAt(0) == '#')
3890         ){
3891             e.preventDefault();
3892         }
3893         
3894         if (this.disabled) {
3895             return;
3896         }
3897         
3898         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3899         if (tg && tg.transition) {
3900             Roo.log("waiting for the transitionend");
3901             return;
3902         }
3903         
3904         Roo.log("fire event clicked");
3905         if(this.fireEvent('click', this, e) === false){
3906             return;
3907         };
3908         
3909         if(this.tagtype == 'span'){
3910             return;
3911         }
3912         
3913         if(this.animateRef && this.href.charAt(0) == '#'){
3914             this.scrollToElement(e);
3915             return;
3916         }
3917         
3918         var p = this.parent();
3919         if (['tabs','pills'].indexOf(p.type)!==-1) {
3920             if (typeof(p.setActiveItem) !== 'undefined') {
3921                 p.setActiveItem(this);
3922             }
3923         }
3924         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
3925         if (p.parentType == 'NavHeaderbar' && !this.menu) {
3926             // remove the collapsed menu expand...
3927             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
3928         }
3929         
3930     },
3931     
3932     isActive: function () {
3933         return this.active
3934     },
3935     setActive : function(state, fire, is_was_active)
3936     {
3937         if (this.active && !state & this.navId) {
3938             this.was_active = true;
3939             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3940             if (nv) {
3941                 nv.clearWasActive(this);
3942             }
3943             
3944         }
3945         this.active = state;
3946         
3947         if (!state ) {
3948             this.el.removeClass('active');
3949         } else if (!this.el.hasClass('active')) {
3950             this.el.addClass('active');
3951         }
3952         if (fire) {
3953             this.fireEvent('changed', this, state);
3954         }
3955         
3956         // show a panel if it's registered and related..
3957         
3958         if (!this.navId || !this.tabId || !state || is_was_active) {
3959             return;
3960         }
3961         
3962         var tg = Roo.bootstrap.TabGroup.get(this.navId);
3963         if (!tg) {
3964             return;
3965         }
3966         var pan = tg.getPanelByName(this.tabId);
3967         if (!pan) {
3968             return;
3969         }
3970         // if we can not flip to new panel - go back to old nav highlight..
3971         if (false == tg.showPanel(pan)) {
3972             var nv = Roo.bootstrap.NavGroup.get(this.navId);
3973             if (nv) {
3974                 var onav = nv.getWasActive();
3975                 if (onav) {
3976                     onav.setActive(true, false, true);
3977                 }
3978             }
3979             
3980         }
3981         
3982         
3983         
3984     },
3985      // this should not be here...
3986     setDisabled : function(state)
3987     {
3988         this.disabled = state;
3989         if (!state ) {
3990             this.el.removeClass('disabled');
3991         } else if (!this.el.hasClass('disabled')) {
3992             this.el.addClass('disabled');
3993         }
3994         
3995     },
3996     
3997     /**
3998      * Fetch the element to display the tooltip on.
3999      * @return {Roo.Element} defaults to this.el
4000      */
4001     tooltipEl : function()
4002     {
4003         return this.el.select('' + this.tagtype + '', true).first();
4004     },
4005     
4006     scrollToElement : function(e)
4007     {
4008         var c = document.body;
4009         
4010         var target = Roo.get(c).select('a[name=' + this.href.replace('#', '') +']', true).first();
4011         
4012         if(!target){
4013             return;
4014         }
4015
4016         var o = target.calcOffsetsTo(c);
4017         
4018         var options = {
4019             target : target,
4020             value : o[1]
4021         }
4022         
4023         this.fireEvent('scrollto', this, options, e);
4024         
4025         Roo.get(c).scrollTo('top', options.value, true);
4026         
4027         return;
4028     }
4029 });
4030  
4031
4032  /*
4033  * - LGPL
4034  *
4035  * sidebar item
4036  *
4037  *  li
4038  *    <span> icon </span>
4039  *    <span> text </span>
4040  *    <span>badge </span>
4041  */
4042
4043 /**
4044  * @class Roo.bootstrap.NavSidebarItem
4045  * @extends Roo.bootstrap.NavItem
4046  * Bootstrap Navbar.NavSidebarItem class
4047  * @constructor
4048  * Create a new Navbar Button
4049  * @param {Object} config The config object
4050  */
4051 Roo.bootstrap.NavSidebarItem = function(config){
4052     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4053     this.addEvents({
4054         // raw events
4055         /**
4056          * @event click
4057          * The raw click event for the entire grid.
4058          * @param {Roo.EventObject} e
4059          */
4060         "click" : true,
4061          /**
4062             * @event changed
4063             * Fires when the active item active state changes
4064             * @param {Roo.bootstrap.NavSidebarItem} this
4065             * @param {boolean} state the new state
4066              
4067          */
4068         'changed': true
4069     });
4070    
4071 };
4072
4073 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4074     
4075     
4076     getAutoCreate : function(){
4077         
4078         
4079         var a = {
4080                 tag: 'a',
4081                 href : this.href || '#',
4082                 cls: '',
4083                 html : '',
4084                 cn : []
4085         };
4086         var cfg = {
4087             tag: 'li',
4088             cls: '',
4089             cn: [ a ]
4090         }
4091         var span = {
4092             tag: 'span',
4093             html : this.html || ''
4094         }
4095         
4096         
4097         if (this.active) {
4098             cfg.cls += ' active';
4099         }
4100         
4101         // left icon..
4102         if (this.glyphicon || this.icon) {
4103             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4104             a.cn.push({ tag : 'i', cls : c }) ;
4105         }
4106         // html..
4107         a.cn.push(span);
4108         // then badge..
4109         if (this.badge !== '') {
4110             a.cn.push({ tag: 'span',  cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge }); 
4111         }
4112         // fi
4113         if (this.menu) {
4114             a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4115             a.cls += 'dropdown-toggle treeview' ;
4116             
4117         }
4118         
4119         
4120         
4121         return cfg;
4122          
4123            
4124     }
4125    
4126      
4127  
4128 });
4129  
4130
4131  /*
4132  * - LGPL
4133  *
4134  * row
4135  * 
4136  */
4137
4138 /**
4139  * @class Roo.bootstrap.Row
4140  * @extends Roo.bootstrap.Component
4141  * Bootstrap Row class (contains columns...)
4142  * 
4143  * @constructor
4144  * Create a new Row
4145  * @param {Object} config The config object
4146  */
4147
4148 Roo.bootstrap.Row = function(config){
4149     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4150 };
4151
4152 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4153     
4154     getAutoCreate : function(){
4155        return {
4156             cls: 'row clearfix'
4157        };
4158     }
4159     
4160     
4161 });
4162
4163  
4164
4165  /*
4166  * - LGPL
4167  *
4168  * element
4169  * 
4170  */
4171
4172 /**
4173  * @class Roo.bootstrap.Element
4174  * @extends Roo.bootstrap.Component
4175  * Bootstrap Element class
4176  * @cfg {String} html contents of the element
4177  * @cfg {String} tag tag of the element
4178  * @cfg {String} cls class of the element
4179  * 
4180  * @constructor
4181  * Create a new Element
4182  * @param {Object} config The config object
4183  */
4184
4185 Roo.bootstrap.Element = function(config){
4186     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4187 };
4188
4189 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4190     
4191     tag: 'div',
4192     cls: '',
4193     html: '',
4194      
4195     
4196     getAutoCreate : function(){
4197         
4198         var cfg = {
4199             tag: this.tag,
4200             cls: this.cls,
4201             html: this.html
4202         }
4203         
4204         
4205         
4206         return cfg;
4207     }
4208    
4209 });
4210
4211  
4212
4213  /*
4214  * - LGPL
4215  *
4216  * pagination
4217  * 
4218  */
4219
4220 /**
4221  * @class Roo.bootstrap.Pagination
4222  * @extends Roo.bootstrap.Component
4223  * Bootstrap Pagination class
4224  * @cfg {String} size xs | sm | md | lg
4225  * @cfg {Boolean} inverse false | true
4226  * 
4227  * @constructor
4228  * Create a new Pagination
4229  * @param {Object} config The config object
4230  */
4231
4232 Roo.bootstrap.Pagination = function(config){
4233     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4234 };
4235
4236 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4237     
4238     cls: false,
4239     size: false,
4240     inverse: false,
4241     
4242     getAutoCreate : function(){
4243         var cfg = {
4244             tag: 'ul',
4245                 cls: 'pagination'
4246         };
4247         if (this.inverse) {
4248             cfg.cls += ' inverse';
4249         }
4250         if (this.html) {
4251             cfg.html=this.html;
4252         }
4253         if (this.cls) {
4254             cfg.cls += " " + this.cls;
4255         }
4256         return cfg;
4257     }
4258    
4259 });
4260
4261  
4262
4263  /*
4264  * - LGPL
4265  *
4266  * Pagination item
4267  * 
4268  */
4269
4270
4271 /**
4272  * @class Roo.bootstrap.PaginationItem
4273  * @extends Roo.bootstrap.Component
4274  * Bootstrap PaginationItem class
4275  * @cfg {String} html text
4276  * @cfg {String} href the link
4277  * @cfg {Boolean} preventDefault (true | false) default true
4278  * @cfg {Boolean} active (true | false) default false
4279  * @cfg {Boolean} disabled default false
4280  * 
4281  * 
4282  * @constructor
4283  * Create a new PaginationItem
4284  * @param {Object} config The config object
4285  */
4286
4287
4288 Roo.bootstrap.PaginationItem = function(config){
4289     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4290     this.addEvents({
4291         // raw events
4292         /**
4293          * @event click
4294          * The raw click event for the entire grid.
4295          * @param {Roo.EventObject} e
4296          */
4297         "click" : true
4298     });
4299 };
4300
4301 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
4302     
4303     href : false,
4304     html : false,
4305     preventDefault: true,
4306     active : false,
4307     cls : false,
4308     disabled: false,
4309     
4310     getAutoCreate : function(){
4311         var cfg= {
4312             tag: 'li',
4313             cn: [
4314                 {
4315                     tag : 'a',
4316                     href : this.href ? this.href : '#',
4317                     html : this.html ? this.html : ''
4318                 }
4319             ]
4320         };
4321         
4322         if(this.cls){
4323             cfg.cls = this.cls;
4324         }
4325         
4326         if(this.disabled){
4327             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4328         }
4329         
4330         if(this.active){
4331             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4332         }
4333         
4334         return cfg;
4335     },
4336     
4337     initEvents: function() {
4338         
4339         this.el.on('click', this.onClick, this);
4340         
4341     },
4342     onClick : function(e)
4343     {
4344         Roo.log('PaginationItem on click ');
4345         if(this.preventDefault){
4346             e.preventDefault();
4347         }
4348         
4349         if(this.disabled){
4350             return;
4351         }
4352         
4353         this.fireEvent('click', this, e);
4354     }
4355    
4356 });
4357
4358  
4359
4360  /*
4361  * - LGPL
4362  *
4363  * slider
4364  * 
4365  */
4366
4367
4368 /**
4369  * @class Roo.bootstrap.Slider
4370  * @extends Roo.bootstrap.Component
4371  * Bootstrap Slider class
4372  *    
4373  * @constructor
4374  * Create a new Slider
4375  * @param {Object} config The config object
4376  */
4377
4378 Roo.bootstrap.Slider = function(config){
4379     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4380 };
4381
4382 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
4383     
4384     getAutoCreate : function(){
4385         
4386         var cfg = {
4387             tag: 'div',
4388             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4389             cn: [
4390                 {
4391                     tag: 'a',
4392                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
4393                 }
4394             ]
4395         }
4396         
4397         return cfg;
4398     }
4399    
4400 });
4401
4402  /*
4403  * Based on:
4404  * Ext JS Library 1.1.1
4405  * Copyright(c) 2006-2007, Ext JS, LLC.
4406  *
4407  * Originally Released Under LGPL - original licence link has changed is not relivant.
4408  *
4409  * Fork - LGPL
4410  * <script type="text/javascript">
4411  */
4412  
4413
4414 /**
4415  * @class Roo.grid.ColumnModel
4416  * @extends Roo.util.Observable
4417  * This is the default implementation of a ColumnModel used by the Grid. It defines
4418  * the columns in the grid.
4419  * <br>Usage:<br>
4420  <pre><code>
4421  var colModel = new Roo.grid.ColumnModel([
4422         {header: "Ticker", width: 60, sortable: true, locked: true},
4423         {header: "Company Name", width: 150, sortable: true},
4424         {header: "Market Cap.", width: 100, sortable: true},
4425         {header: "$ Sales", width: 100, sortable: true, renderer: money},
4426         {header: "Employees", width: 100, sortable: true, resizable: false}
4427  ]);
4428  </code></pre>
4429  * <p>
4430  
4431  * The config options listed for this class are options which may appear in each
4432  * individual column definition.
4433  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4434  * @constructor
4435  * @param {Object} config An Array of column config objects. See this class's
4436  * config objects for details.
4437 */
4438 Roo.grid.ColumnModel = function(config){
4439         /**
4440      * The config passed into the constructor
4441      */
4442     this.config = config;
4443     this.lookup = {};
4444
4445     // if no id, create one
4446     // if the column does not have a dataIndex mapping,
4447     // map it to the order it is in the config
4448     for(var i = 0, len = config.length; i < len; i++){
4449         var c = config[i];
4450         if(typeof c.dataIndex == "undefined"){
4451             c.dataIndex = i;
4452         }
4453         if(typeof c.renderer == "string"){
4454             c.renderer = Roo.util.Format[c.renderer];
4455         }
4456         if(typeof c.id == "undefined"){
4457             c.id = Roo.id();
4458         }
4459         if(c.editor && c.editor.xtype){
4460             c.editor  = Roo.factory(c.editor, Roo.grid);
4461         }
4462         if(c.editor && c.editor.isFormField){
4463             c.editor = new Roo.grid.GridEditor(c.editor);
4464         }
4465         this.lookup[c.id] = c;
4466     }
4467
4468     /**
4469      * The width of columns which have no width specified (defaults to 100)
4470      * @type Number
4471      */
4472     this.defaultWidth = 100;
4473
4474     /**
4475      * Default sortable of columns which have no sortable specified (defaults to false)
4476      * @type Boolean
4477      */
4478     this.defaultSortable = false;
4479
4480     this.addEvents({
4481         /**
4482              * @event widthchange
4483              * Fires when the width of a column changes.
4484              * @param {ColumnModel} this
4485              * @param {Number} columnIndex The column index
4486              * @param {Number} newWidth The new width
4487              */
4488             "widthchange": true,
4489         /**
4490              * @event headerchange
4491              * Fires when the text of a header changes.
4492              * @param {ColumnModel} this
4493              * @param {Number} columnIndex The column index
4494              * @param {Number} newText The new header text
4495              */
4496             "headerchange": true,
4497         /**
4498              * @event hiddenchange
4499              * Fires when a column is hidden or "unhidden".
4500              * @param {ColumnModel} this
4501              * @param {Number} columnIndex The column index
4502              * @param {Boolean} hidden true if hidden, false otherwise
4503              */
4504             "hiddenchange": true,
4505             /**
4506          * @event columnmoved
4507          * Fires when a column is moved.
4508          * @param {ColumnModel} this
4509          * @param {Number} oldIndex
4510          * @param {Number} newIndex
4511          */
4512         "columnmoved" : true,
4513         /**
4514          * @event columlockchange
4515          * Fires when a column's locked state is changed
4516          * @param {ColumnModel} this
4517          * @param {Number} colIndex
4518          * @param {Boolean} locked true if locked
4519          */
4520         "columnlockchange" : true
4521     });
4522     Roo.grid.ColumnModel.superclass.constructor.call(this);
4523 };
4524 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4525     /**
4526      * @cfg {String} header The header text to display in the Grid view.
4527      */
4528     /**
4529      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4530      * {@link Roo.data.Record} definition from which to draw the column's value. If not
4531      * specified, the column's index is used as an index into the Record's data Array.
4532      */
4533     /**
4534      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4535      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4536      */
4537     /**
4538      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4539      * Defaults to the value of the {@link #defaultSortable} property.
4540      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4541      */
4542     /**
4543      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
4544      */
4545     /**
4546      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
4547      */
4548     /**
4549      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4550      */
4551     /**
4552      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4553      */
4554     /**
4555      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4556      * given the cell's data value. See {@link #setRenderer}. If not specified, the
4557      * default renderer uses the raw data value. If an object is returned (bootstrap only)
4558      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4559      */
4560        /**
4561      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
4562      */
4563     /**
4564      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
4565      */
4566     /**
4567      * @cfg {String} cursor (Optional)
4568      */
4569     /**
4570      * @cfg {String} tooltip (Optional)
4571      */
4572     /**
4573      * Returns the id of the column at the specified index.
4574      * @param {Number} index The column index
4575      * @return {String} the id
4576      */
4577     getColumnId : function(index){
4578         return this.config[index].id;
4579     },
4580
4581     /**
4582      * Returns the column for a specified id.
4583      * @param {String} id The column id
4584      * @return {Object} the column
4585      */
4586     getColumnById : function(id){
4587         return this.lookup[id];
4588     },
4589
4590     
4591     /**
4592      * Returns the column for a specified dataIndex.
4593      * @param {String} dataIndex The column dataIndex
4594      * @return {Object|Boolean} the column or false if not found
4595      */
4596     getColumnByDataIndex: function(dataIndex){
4597         var index = this.findColumnIndex(dataIndex);
4598         return index > -1 ? this.config[index] : false;
4599     },
4600     
4601     /**
4602      * Returns the index for a specified column id.
4603      * @param {String} id The column id
4604      * @return {Number} the index, or -1 if not found
4605      */
4606     getIndexById : function(id){
4607         for(var i = 0, len = this.config.length; i < len; i++){
4608             if(this.config[i].id == id){
4609                 return i;
4610             }
4611         }
4612         return -1;
4613     },
4614     
4615     /**
4616      * Returns the index for a specified column dataIndex.
4617      * @param {String} dataIndex The column dataIndex
4618      * @return {Number} the index, or -1 if not found
4619      */
4620     
4621     findColumnIndex : function(dataIndex){
4622         for(var i = 0, len = this.config.length; i < len; i++){
4623             if(this.config[i].dataIndex == dataIndex){
4624                 return i;
4625             }
4626         }
4627         return -1;
4628     },
4629     
4630     
4631     moveColumn : function(oldIndex, newIndex){
4632         var c = this.config[oldIndex];
4633         this.config.splice(oldIndex, 1);
4634         this.config.splice(newIndex, 0, c);
4635         this.dataMap = null;
4636         this.fireEvent("columnmoved", this, oldIndex, newIndex);
4637     },
4638
4639     isLocked : function(colIndex){
4640         return this.config[colIndex].locked === true;
4641     },
4642
4643     setLocked : function(colIndex, value, suppressEvent){
4644         if(this.isLocked(colIndex) == value){
4645             return;
4646         }
4647         this.config[colIndex].locked = value;
4648         if(!suppressEvent){
4649             this.fireEvent("columnlockchange", this, colIndex, value);
4650         }
4651     },
4652
4653     getTotalLockedWidth : function(){
4654         var totalWidth = 0;
4655         for(var i = 0; i < this.config.length; i++){
4656             if(this.isLocked(i) && !this.isHidden(i)){
4657                 this.totalWidth += this.getColumnWidth(i);
4658             }
4659         }
4660         return totalWidth;
4661     },
4662
4663     getLockedCount : function(){
4664         for(var i = 0, len = this.config.length; i < len; i++){
4665             if(!this.isLocked(i)){
4666                 return i;
4667             }
4668         }
4669     },
4670
4671     /**
4672      * Returns the number of columns.
4673      * @return {Number}
4674      */
4675     getColumnCount : function(visibleOnly){
4676         if(visibleOnly === true){
4677             var c = 0;
4678             for(var i = 0, len = this.config.length; i < len; i++){
4679                 if(!this.isHidden(i)){
4680                     c++;
4681                 }
4682             }
4683             return c;
4684         }
4685         return this.config.length;
4686     },
4687
4688     /**
4689      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4690      * @param {Function} fn
4691      * @param {Object} scope (optional)
4692      * @return {Array} result
4693      */
4694     getColumnsBy : function(fn, scope){
4695         var r = [];
4696         for(var i = 0, len = this.config.length; i < len; i++){
4697             var c = this.config[i];
4698             if(fn.call(scope||this, c, i) === true){
4699                 r[r.length] = c;
4700             }
4701         }
4702         return r;
4703     },
4704
4705     /**
4706      * Returns true if the specified column is sortable.
4707      * @param {Number} col The column index
4708      * @return {Boolean}
4709      */
4710     isSortable : function(col){
4711         if(typeof this.config[col].sortable == "undefined"){
4712             return this.defaultSortable;
4713         }
4714         return this.config[col].sortable;
4715     },
4716
4717     /**
4718      * Returns the rendering (formatting) function defined for the column.
4719      * @param {Number} col The column index.
4720      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4721      */
4722     getRenderer : function(col){
4723         if(!this.config[col].renderer){
4724             return Roo.grid.ColumnModel.defaultRenderer;
4725         }
4726         return this.config[col].renderer;
4727     },
4728
4729     /**
4730      * Sets the rendering (formatting) function for a column.
4731      * @param {Number} col The column index
4732      * @param {Function} fn The function to use to process the cell's raw data
4733      * to return HTML markup for the grid view. The render function is called with
4734      * the following parameters:<ul>
4735      * <li>Data value.</li>
4736      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4737      * <li>css A CSS style string to apply to the table cell.</li>
4738      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4739      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4740      * <li>Row index</li>
4741      * <li>Column index</li>
4742      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4743      */
4744     setRenderer : function(col, fn){
4745         this.config[col].renderer = fn;
4746     },
4747
4748     /**
4749      * Returns the width for the specified column.
4750      * @param {Number} col The column index
4751      * @return {Number}
4752      */
4753     getColumnWidth : function(col){
4754         return this.config[col].width * 1 || this.defaultWidth;
4755     },
4756
4757     /**
4758      * Sets the width for a column.
4759      * @param {Number} col The column index
4760      * @param {Number} width The new width
4761      */
4762     setColumnWidth : function(col, width, suppressEvent){
4763         this.config[col].width = width;
4764         this.totalWidth = null;
4765         if(!suppressEvent){
4766              this.fireEvent("widthchange", this, col, width);
4767         }
4768     },
4769
4770     /**
4771      * Returns the total width of all columns.
4772      * @param {Boolean} includeHidden True to include hidden column widths
4773      * @return {Number}
4774      */
4775     getTotalWidth : function(includeHidden){
4776         if(!this.totalWidth){
4777             this.totalWidth = 0;
4778             for(var i = 0, len = this.config.length; i < len; i++){
4779                 if(includeHidden || !this.isHidden(i)){
4780                     this.totalWidth += this.getColumnWidth(i);
4781                 }
4782             }
4783         }
4784         return this.totalWidth;
4785     },
4786
4787     /**
4788      * Returns the header for the specified column.
4789      * @param {Number} col The column index
4790      * @return {String}
4791      */
4792     getColumnHeader : function(col){
4793         return this.config[col].header;
4794     },
4795
4796     /**
4797      * Sets the header for a column.
4798      * @param {Number} col The column index
4799      * @param {String} header The new header
4800      */
4801     setColumnHeader : function(col, header){
4802         this.config[col].header = header;
4803         this.fireEvent("headerchange", this, col, header);
4804     },
4805
4806     /**
4807      * Returns the tooltip for the specified column.
4808      * @param {Number} col The column index
4809      * @return {String}
4810      */
4811     getColumnTooltip : function(col){
4812             return this.config[col].tooltip;
4813     },
4814     /**
4815      * Sets the tooltip for a column.
4816      * @param {Number} col The column index
4817      * @param {String} tooltip The new tooltip
4818      */
4819     setColumnTooltip : function(col, tooltip){
4820             this.config[col].tooltip = tooltip;
4821     },
4822
4823     /**
4824      * Returns the dataIndex for the specified column.
4825      * @param {Number} col The column index
4826      * @return {Number}
4827      */
4828     getDataIndex : function(col){
4829         return this.config[col].dataIndex;
4830     },
4831
4832     /**
4833      * Sets the dataIndex for a column.
4834      * @param {Number} col The column index
4835      * @param {Number} dataIndex The new dataIndex
4836      */
4837     setDataIndex : function(col, dataIndex){
4838         this.config[col].dataIndex = dataIndex;
4839     },
4840
4841     
4842     
4843     /**
4844      * Returns true if the cell is editable.
4845      * @param {Number} colIndex The column index
4846      * @param {Number} rowIndex The row index
4847      * @return {Boolean}
4848      */
4849     isCellEditable : function(colIndex, rowIndex){
4850         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4851     },
4852
4853     /**
4854      * Returns the editor defined for the cell/column.
4855      * return false or null to disable editing.
4856      * @param {Number} colIndex The column index
4857      * @param {Number} rowIndex The row index
4858      * @return {Object}
4859      */
4860     getCellEditor : function(colIndex, rowIndex){
4861         return this.config[colIndex].editor;
4862     },
4863
4864     /**
4865      * Sets if a column is editable.
4866      * @param {Number} col The column index
4867      * @param {Boolean} editable True if the column is editable
4868      */
4869     setEditable : function(col, editable){
4870         this.config[col].editable = editable;
4871     },
4872
4873
4874     /**
4875      * Returns true if the column is hidden.
4876      * @param {Number} colIndex The column index
4877      * @return {Boolean}
4878      */
4879     isHidden : function(colIndex){
4880         return this.config[colIndex].hidden;
4881     },
4882
4883
4884     /**
4885      * Returns true if the column width cannot be changed
4886      */
4887     isFixed : function(colIndex){
4888         return this.config[colIndex].fixed;
4889     },
4890
4891     /**
4892      * Returns true if the column can be resized
4893      * @return {Boolean}
4894      */
4895     isResizable : function(colIndex){
4896         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4897     },
4898     /**
4899      * Sets if a column is hidden.
4900      * @param {Number} colIndex The column index
4901      * @param {Boolean} hidden True if the column is hidden
4902      */
4903     setHidden : function(colIndex, hidden){
4904         this.config[colIndex].hidden = hidden;
4905         this.totalWidth = null;
4906         this.fireEvent("hiddenchange", this, colIndex, hidden);
4907     },
4908
4909     /**
4910      * Sets the editor for a column.
4911      * @param {Number} col The column index
4912      * @param {Object} editor The editor object
4913      */
4914     setEditor : function(col, editor){
4915         this.config[col].editor = editor;
4916     }
4917 });
4918
4919 Roo.grid.ColumnModel.defaultRenderer = function(value){
4920         if(typeof value == "string" && value.length < 1){
4921             return "&#160;";
4922         }
4923         return value;
4924 };
4925
4926 // Alias for backwards compatibility
4927 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4928 /*
4929  * Based on:
4930  * Ext JS Library 1.1.1
4931  * Copyright(c) 2006-2007, Ext JS, LLC.
4932  *
4933  * Originally Released Under LGPL - original licence link has changed is not relivant.
4934  *
4935  * Fork - LGPL
4936  * <script type="text/javascript">
4937  */
4938  
4939 /**
4940  * @class Roo.LoadMask
4941  * A simple utility class for generically masking elements while loading data.  If the element being masked has
4942  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4943  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
4944  * element's UpdateManager load indicator and will be destroyed after the initial load.
4945  * @constructor
4946  * Create a new LoadMask
4947  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4948  * @param {Object} config The config object
4949  */
4950 Roo.LoadMask = function(el, config){
4951     this.el = Roo.get(el);
4952     Roo.apply(this, config);
4953     if(this.store){
4954         this.store.on('beforeload', this.onBeforeLoad, this);
4955         this.store.on('load', this.onLoad, this);
4956         this.store.on('loadexception', this.onLoadException, this);
4957         this.removeMask = false;
4958     }else{
4959         var um = this.el.getUpdateManager();
4960         um.showLoadIndicator = false; // disable the default indicator
4961         um.on('beforeupdate', this.onBeforeLoad, this);
4962         um.on('update', this.onLoad, this);
4963         um.on('failure', this.onLoad, this);
4964         this.removeMask = true;
4965     }
4966 };
4967
4968 Roo.LoadMask.prototype = {
4969     /**
4970      * @cfg {Boolean} removeMask
4971      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4972      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
4973      */
4974     /**
4975      * @cfg {String} msg
4976      * The text to display in a centered loading message box (defaults to 'Loading...')
4977      */
4978     msg : 'Loading...',
4979     /**
4980      * @cfg {String} msgCls
4981      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4982      */
4983     msgCls : 'x-mask-loading',
4984
4985     /**
4986      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4987      * @type Boolean
4988      */
4989     disabled: false,
4990
4991     /**
4992      * Disables the mask to prevent it from being displayed
4993      */
4994     disable : function(){
4995        this.disabled = true;
4996     },
4997
4998     /**
4999      * Enables the mask so that it can be displayed
5000      */
5001     enable : function(){
5002         this.disabled = false;
5003     },
5004     
5005     onLoadException : function()
5006     {
5007         Roo.log(arguments);
5008         
5009         if (typeof(arguments[3]) != 'undefined') {
5010             Roo.MessageBox.alert("Error loading",arguments[3]);
5011         } 
5012         /*
5013         try {
5014             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5015                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5016             }   
5017         } catch(e) {
5018             
5019         }
5020         */
5021     
5022         
5023         
5024         this.el.unmask(this.removeMask);
5025     },
5026     // private
5027     onLoad : function()
5028     {
5029         this.el.unmask(this.removeMask);
5030     },
5031
5032     // private
5033     onBeforeLoad : function(){
5034         if(!this.disabled){
5035             this.el.mask(this.msg, this.msgCls);
5036         }
5037     },
5038
5039     // private
5040     destroy : function(){
5041         if(this.store){
5042             this.store.un('beforeload', this.onBeforeLoad, this);
5043             this.store.un('load', this.onLoad, this);
5044             this.store.un('loadexception', this.onLoadException, this);
5045         }else{
5046             var um = this.el.getUpdateManager();
5047             um.un('beforeupdate', this.onBeforeLoad, this);
5048             um.un('update', this.onLoad, this);
5049             um.un('failure', this.onLoad, this);
5050         }
5051     }
5052 };/*
5053  * - LGPL
5054  *
5055  * table
5056  * 
5057  */
5058
5059 /**
5060  * @class Roo.bootstrap.Table
5061  * @extends Roo.bootstrap.Component
5062  * Bootstrap Table class
5063  * @cfg {String} cls table class
5064  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5065  * @cfg {String} bgcolor Specifies the background color for a table
5066  * @cfg {Number} border Specifies whether the table cells should have borders or not
5067  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5068  * @cfg {Number} cellspacing Specifies the space between cells
5069  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5070  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5071  * @cfg {String} sortable Specifies that the table should be sortable
5072  * @cfg {String} summary Specifies a summary of the content of a table
5073  * @cfg {Number} width Specifies the width of a table
5074  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5075  * 
5076  * @cfg {boolean} striped Should the rows be alternative striped
5077  * @cfg {boolean} bordered Add borders to the table
5078  * @cfg {boolean} hover Add hover highlighting
5079  * @cfg {boolean} condensed Format condensed
5080  * @cfg {boolean} responsive Format condensed
5081  * @cfg {Boolean} loadMask (true|false) default false
5082  * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5083  * @cfg {Boolean} thead (true|false) generate thead, default true
5084  * @cfg {Boolean} RowSelection (true|false) default false
5085  * @cfg {Boolean} CellSelection (true|false) default false
5086  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5087  
5088  * 
5089  * @constructor
5090  * Create a new Table
5091  * @param {Object} config The config object
5092  */
5093
5094 Roo.bootstrap.Table = function(config){
5095     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5096     
5097     if (this.sm) {
5098         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5099         this.sm = this.selModel;
5100         this.sm.xmodule = this.xmodule || false;
5101     }
5102     if (this.cm && typeof(this.cm.config) == 'undefined') {
5103         this.colModel = new Roo.grid.ColumnModel(this.cm);
5104         this.cm = this.colModel;
5105         this.cm.xmodule = this.xmodule || false;
5106     }
5107     if (this.store) {
5108         this.store= Roo.factory(this.store, Roo.data);
5109         this.ds = this.store;
5110         this.ds.xmodule = this.xmodule || false;
5111          
5112     }
5113     if (this.footer && this.store) {
5114         this.footer.dataSource = this.ds;
5115         this.footer = Roo.factory(this.footer);
5116     }
5117     
5118     /** @private */
5119     this.addEvents({
5120         /**
5121          * @event cellclick
5122          * Fires when a cell is clicked
5123          * @param {Roo.bootstrap.Table} this
5124          * @param {Roo.Element} el
5125          * @param {Number} rowIndex
5126          * @param {Number} columnIndex
5127          * @param {Roo.EventObject} e
5128          */
5129         "cellclick" : true,
5130         /**
5131          * @event celldblclick
5132          * Fires when a cell is double clicked
5133          * @param {Roo.bootstrap.Table} this
5134          * @param {Roo.Element} el
5135          * @param {Number} rowIndex
5136          * @param {Number} columnIndex
5137          * @param {Roo.EventObject} e
5138          */
5139         "celldblclick" : true,
5140         /**
5141          * @event rowclick
5142          * Fires when a row is clicked
5143          * @param {Roo.bootstrap.Table} this
5144          * @param {Roo.Element} el
5145          * @param {Number} rowIndex
5146          * @param {Roo.EventObject} e
5147          */
5148         "rowclick" : true,
5149         /**
5150          * @event rowdblclick
5151          * Fires when a row is double clicked
5152          * @param {Roo.bootstrap.Table} this
5153          * @param {Roo.Element} el
5154          * @param {Number} rowIndex
5155          * @param {Roo.EventObject} e
5156          */
5157         "rowdblclick" : true,
5158         /**
5159          * @event mouseover
5160          * Fires when a mouseover occur
5161          * @param {Roo.bootstrap.Table} this
5162          * @param {Roo.Element} el
5163          * @param {Number} rowIndex
5164          * @param {Number} columnIndex
5165          * @param {Roo.EventObject} e
5166          */
5167         "mouseover" : true,
5168         /**
5169          * @event mouseout
5170          * Fires when a mouseout occur
5171          * @param {Roo.bootstrap.Table} this
5172          * @param {Roo.Element} el
5173          * @param {Number} rowIndex
5174          * @param {Number} columnIndex
5175          * @param {Roo.EventObject} e
5176          */
5177         "mouseout" : true,
5178         /**
5179          * @event rowclass
5180          * Fires when a row is rendered, so you can change add a style to it.
5181          * @param {Roo.bootstrap.Table} this
5182          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5183          */
5184         'rowclass' : true,
5185           /**
5186          * @event rowsrendered
5187          * Fires when all the  rows have been rendered
5188          * @param {Roo.bootstrap.Table} this
5189          */
5190         'rowsrendered' : true
5191         
5192     });
5193 };
5194
5195 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
5196     
5197     cls: false,
5198     align: false,
5199     bgcolor: false,
5200     border: false,
5201     cellpadding: false,
5202     cellspacing: false,
5203     frame: false,
5204     rules: false,
5205     sortable: false,
5206     summary: false,
5207     width: false,
5208     striped : false,
5209     bordered: false,
5210     hover:  false,
5211     condensed : false,
5212     responsive : false,
5213     sm : false,
5214     cm : false,
5215     store : false,
5216     loadMask : false,
5217     tfoot : true,
5218     thead : true,
5219     RowSelection : false,
5220     CellSelection : false,
5221     layout : false,
5222     
5223     // Roo.Element - the tbody
5224     mainBody: false, 
5225     
5226     getAutoCreate : function(){
5227         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5228         
5229         cfg = {
5230             tag: 'table',
5231             cls : 'table',
5232             cn : []
5233         }
5234             
5235         if (this.striped) {
5236             cfg.cls += ' table-striped';
5237         }
5238         
5239         if (this.hover) {
5240             cfg.cls += ' table-hover';
5241         }
5242         if (this.bordered) {
5243             cfg.cls += ' table-bordered';
5244         }
5245         if (this.condensed) {
5246             cfg.cls += ' table-condensed';
5247         }
5248         if (this.responsive) {
5249             cfg.cls += ' table-responsive';
5250         }
5251         
5252         if (this.cls) {
5253             cfg.cls+=  ' ' +this.cls;
5254         }
5255         
5256         // this lot should be simplifed...
5257         
5258         if (this.align) {
5259             cfg.align=this.align;
5260         }
5261         if (this.bgcolor) {
5262             cfg.bgcolor=this.bgcolor;
5263         }
5264         if (this.border) {
5265             cfg.border=this.border;
5266         }
5267         if (this.cellpadding) {
5268             cfg.cellpadding=this.cellpadding;
5269         }
5270         if (this.cellspacing) {
5271             cfg.cellspacing=this.cellspacing;
5272         }
5273         if (this.frame) {
5274             cfg.frame=this.frame;
5275         }
5276         if (this.rules) {
5277             cfg.rules=this.rules;
5278         }
5279         if (this.sortable) {
5280             cfg.sortable=this.sortable;
5281         }
5282         if (this.summary) {
5283             cfg.summary=this.summary;
5284         }
5285         if (this.width) {
5286             cfg.width=this.width;
5287         }
5288         if (this.layout) {
5289             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5290         }
5291         
5292         if(this.store || this.cm){
5293             if(this.thead){
5294                 cfg.cn.push(this.renderHeader());
5295             }
5296             
5297             cfg.cn.push(this.renderBody());
5298             
5299             if(this.tfoot){
5300                 cfg.cn.push(this.renderFooter());
5301             }
5302             
5303             cfg.cls+=  ' TableGrid';
5304         }
5305         
5306         return { cn : [ cfg ] };
5307     },
5308     
5309     initEvents : function()
5310     {   
5311         if(!this.store || !this.cm){
5312             return;
5313         }
5314         
5315         //Roo.log('initEvents with ds!!!!');
5316         
5317         this.mainBody = this.el.select('tbody', true).first();
5318         
5319         
5320         var _this = this;
5321         
5322         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5323             e.on('click', _this.sort, _this);
5324         });
5325         
5326         this.el.on("click", this.onClick, this);
5327         this.el.on("dblclick", this.onDblClick, this);
5328         
5329         // why is this done????? = it breaks dialogs??
5330         //this.parent().el.setStyle('position', 'relative');
5331         
5332         
5333         if (this.footer) {
5334             this.footer.parentId = this.id;
5335             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
5336         }
5337         
5338         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5339         
5340         this.store.on('load', this.onLoad, this);
5341         this.store.on('beforeload', this.onBeforeLoad, this);
5342         this.store.on('update', this.onUpdate, this);
5343         this.store.on('add', this.onAdd, this);
5344         
5345     },
5346     
5347     onMouseover : function(e, el)
5348     {
5349         var cell = Roo.get(el);
5350         
5351         if(!cell){
5352             return;
5353         }
5354         
5355         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5356             cell = cell.findParent('td', false, true);
5357         }
5358         
5359         var row = cell.findParent('tr', false, true);
5360         var cellIndex = cell.dom.cellIndex;
5361         var rowIndex = row.dom.rowIndex - 1; // start from 0
5362         
5363         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5364         
5365     },
5366     
5367     onMouseout : function(e, el)
5368     {
5369         var cell = Roo.get(el);
5370         
5371         if(!cell){
5372             return;
5373         }
5374         
5375         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5376             cell = cell.findParent('td', false, true);
5377         }
5378         
5379         var row = cell.findParent('tr', false, true);
5380         var cellIndex = cell.dom.cellIndex;
5381         var rowIndex = row.dom.rowIndex - 1; // start from 0
5382         
5383         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5384         
5385     },
5386     
5387     onClick : function(e, el)
5388     {
5389         var cell = Roo.get(el);
5390         
5391         if(!cell || (!this.CellSelection && !this.RowSelection)){
5392             return;
5393         }
5394         
5395         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5396             cell = cell.findParent('td', false, true);
5397         }
5398         
5399         if(!cell || typeof(cell) == 'undefined'){
5400             return;
5401         }
5402         
5403         var row = cell.findParent('tr', false, true);
5404         
5405         if(!row || typeof(row) == 'undefined'){
5406             return;
5407         }
5408         
5409         var cellIndex = cell.dom.cellIndex;
5410         var rowIndex = this.getRowIndex(row);
5411         
5412         if(this.CellSelection){
5413             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5414         }
5415         
5416         if(this.RowSelection){
5417             this.fireEvent('rowclick', this, row, rowIndex, e);
5418         }
5419         
5420         
5421     },
5422     
5423     onDblClick : function(e,el)
5424     {
5425         var cell = Roo.get(el);
5426         
5427         if(!cell || (!this.CellSelection && !this.RowSelection)){
5428             return;
5429         }
5430         
5431         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5432             cell = cell.findParent('td', false, true);
5433         }
5434         
5435         if(!cell || typeof(cell) == 'undefined'){
5436             return;
5437         }
5438         
5439         var row = cell.findParent('tr', false, true);
5440         
5441         if(!row || typeof(row) == 'undefined'){
5442             return;
5443         }
5444         
5445         var cellIndex = cell.dom.cellIndex;
5446         var rowIndex = this.getRowIndex(row);
5447         
5448         if(this.CellSelection){
5449             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5450         }
5451         
5452         if(this.RowSelection){
5453             this.fireEvent('rowdblclick', this, row, rowIndex, e);
5454         }
5455     },
5456     
5457     sort : function(e,el)
5458     {
5459         var col = Roo.get(el);
5460         
5461         if(!col.hasClass('sortable')){
5462             return;
5463         }
5464         
5465         var sort = col.attr('sort');
5466         var dir = 'ASC';
5467         
5468         if(col.hasClass('glyphicon-arrow-up')){
5469             dir = 'DESC';
5470         }
5471         
5472         this.store.sortInfo = {field : sort, direction : dir};
5473         
5474         if (this.footer) {
5475             Roo.log("calling footer first");
5476             this.footer.onClick('first');
5477         } else {
5478         
5479             this.store.load({ params : { start : 0 } });
5480         }
5481     },
5482     
5483     renderHeader : function()
5484     {
5485         var header = {
5486             tag: 'thead',
5487             cn : []
5488         };
5489         
5490         var cm = this.cm;
5491         
5492         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5493             
5494             var config = cm.config[i];
5495                     
5496             var c = {
5497                 tag: 'th',
5498                 style : '',
5499                 html: cm.getColumnHeader(i)
5500             };
5501             
5502             if(typeof(config.tooltip) != 'undefined'){
5503                 c.tooltip = config.tooltip;
5504             }
5505             
5506             if(typeof(config.colspan) != 'undefined'){
5507                 c.colspan = config.colspan;
5508             }
5509             
5510             if(typeof(config.hidden) != 'undefined' && config.hidden){
5511                 c.style += ' display:none;';
5512             }
5513             
5514             if(typeof(config.dataIndex) != 'undefined'){
5515                 c.sort = config.dataIndex;
5516             }
5517             
5518             if(typeof(config.sortable) != 'undefined' && config.sortable){
5519                 c.cls = 'sortable';
5520             }
5521             
5522             if(typeof(config.align) != 'undefined' && config.align.length){
5523                 c.style += ' text-align:' + config.align + ';';
5524             }
5525             
5526             if(typeof(config.width) != 'undefined'){
5527                 c.style += ' width:' + config.width + 'px;';
5528             }
5529             
5530             header.cn.push(c)
5531         }
5532         
5533         return header;
5534     },
5535     
5536     renderBody : function()
5537     {
5538         var body = {
5539             tag: 'tbody',
5540             cn : [
5541                 {
5542                     tag: 'tr',
5543                     cn : [
5544                         {
5545                             tag : 'td',
5546                             colspan :  this.cm.getColumnCount()
5547                         }
5548                     ]
5549                 }
5550             ]
5551         };
5552         
5553         return body;
5554     },
5555     
5556     renderFooter : function()
5557     {
5558         var footer = {
5559             tag: 'tfoot',
5560             cn : [
5561                 {
5562                     tag: 'tr',
5563                     cn : [
5564                         {
5565                             tag : 'td',
5566                             colspan :  this.cm.getColumnCount()
5567                         }
5568                     ]
5569                 }
5570             ]
5571         };
5572         
5573         return footer;
5574     },
5575     
5576     
5577     
5578     onLoad : function()
5579     {
5580         Roo.log('ds onload');
5581         this.clear();
5582         
5583         var _this = this;
5584         var cm = this.cm;
5585         var ds = this.store;
5586         
5587         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5588             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5589             
5590             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5591                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5592             }
5593             
5594             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5595                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5596             }
5597         });
5598         
5599         var tbody =  this.mainBody;
5600               
5601         if(ds.getCount() > 0){
5602             ds.data.each(function(d,rowIndex){
5603                 var row =  this.renderRow(cm, ds, rowIndex);
5604                 
5605                 tbody.createChild(row);
5606                 
5607                 var _this = this;
5608                 
5609                 if(row.cellObjects.length){
5610                     Roo.each(row.cellObjects, function(r){
5611                         _this.renderCellObject(r);
5612                     })
5613                 }
5614                 
5615             }, this);
5616         }
5617         
5618         Roo.each(this.el.select('tbody td', true).elements, function(e){
5619             e.on('mouseover', _this.onMouseover, _this);
5620         });
5621         
5622         Roo.each(this.el.select('tbody td', true).elements, function(e){
5623             e.on('mouseout', _this.onMouseout, _this);
5624         });
5625         this.fireEvent('rowsrendered', this);
5626         //if(this.loadMask){
5627         //    this.maskEl.hide();
5628         //}
5629     },
5630     
5631     
5632     onUpdate : function(ds,record)
5633     {
5634         this.refreshRow(record);
5635     },
5636     
5637     onRemove : function(ds, record, index, isUpdate){
5638         if(isUpdate !== true){
5639             this.fireEvent("beforerowremoved", this, index, record);
5640         }
5641         var bt = this.mainBody.dom;
5642         
5643         var rows = this.el.select('tbody > tr', true).elements;
5644         
5645         if(typeof(rows[index]) != 'undefined'){
5646             bt.removeChild(rows[index].dom);
5647         }
5648         
5649 //        if(bt.rows[index]){
5650 //            bt.removeChild(bt.rows[index]);
5651 //        }
5652         
5653         if(isUpdate !== true){
5654             //this.stripeRows(index);
5655             //this.syncRowHeights(index, index);
5656             //this.layout();
5657             this.fireEvent("rowremoved", this, index, record);
5658         }
5659     },
5660     
5661     onAdd : function(ds, records, rowIndex)
5662     {
5663         //Roo.log('on Add called');
5664         // - note this does not handle multiple adding very well..
5665         var bt = this.mainBody.dom;
5666         for (var i =0 ; i < records.length;i++) {
5667             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5668             //Roo.log(records[i]);
5669             //Roo.log(this.store.getAt(rowIndex+i));
5670             this.insertRow(this.store, rowIndex + i, false);
5671             return;
5672         }
5673         
5674     },
5675     
5676     
5677     refreshRow : function(record){
5678         var ds = this.store, index;
5679         if(typeof record == 'number'){
5680             index = record;
5681             record = ds.getAt(index);
5682         }else{
5683             index = ds.indexOf(record);
5684         }
5685         this.insertRow(ds, index, true);
5686         this.onRemove(ds, record, index+1, true);
5687         //this.syncRowHeights(index, index);
5688         //this.layout();
5689         this.fireEvent("rowupdated", this, index, record);
5690     },
5691     
5692     insertRow : function(dm, rowIndex, isUpdate){
5693         
5694         if(!isUpdate){
5695             this.fireEvent("beforerowsinserted", this, rowIndex);
5696         }
5697             //var s = this.getScrollState();
5698         var row = this.renderRow(this.cm, this.store, rowIndex);
5699         // insert before rowIndex..
5700         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5701         
5702         var _this = this;
5703                 
5704         if(row.cellObjects.length){
5705             Roo.each(row.cellObjects, function(r){
5706                 _this.renderCellObject(r);
5707             })
5708         }
5709             
5710         if(!isUpdate){
5711             this.fireEvent("rowsinserted", this, rowIndex);
5712             //this.syncRowHeights(firstRow, lastRow);
5713             //this.stripeRows(firstRow);
5714             //this.layout();
5715         }
5716         
5717     },
5718     
5719     
5720     getRowDom : function(rowIndex)
5721     {
5722         var rows = this.el.select('tbody > tr', true).elements;
5723         
5724         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5725         
5726     },
5727     // returns the object tree for a tr..
5728   
5729     
5730     renderRow : function(cm, ds, rowIndex) 
5731     {
5732         
5733         var d = ds.getAt(rowIndex);
5734         
5735         var row = {
5736             tag : 'tr',
5737             cn : []
5738         };
5739             
5740         var cellObjects = [];
5741         
5742         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5743             var config = cm.config[i];
5744             
5745             var renderer = cm.getRenderer(i);
5746             var value = '';
5747             var id = false;
5748             
5749             if(typeof(renderer) !== 'undefined'){
5750                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5751             }
5752             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5753             // and are rendered into the cells after the row is rendered - using the id for the element.
5754             
5755             if(typeof(value) === 'object'){
5756                 id = Roo.id();
5757                 cellObjects.push({
5758                     container : id,
5759                     cfg : value 
5760                 })
5761             }
5762             
5763             var rowcfg = {
5764                 record: d,
5765                 rowIndex : rowIndex,
5766                 colIndex : i,
5767                 rowClass : ''
5768             }
5769
5770             this.fireEvent('rowclass', this, rowcfg);
5771             
5772             var td = {
5773                 tag: 'td',
5774                 cls : rowcfg.rowClass,
5775                 style: '',
5776                 html: (typeof(value) === 'object') ? '' : value
5777             };
5778             
5779             if (id) {
5780                 td.id = id;
5781             }
5782             
5783             if(typeof(config.colspan) != 'undefined'){
5784                 td.colspan = config.colspan;
5785             }
5786             
5787             if(typeof(config.hidden) != 'undefined' && config.hidden){
5788                 td.style += ' display:none;';
5789             }
5790             
5791             if(typeof(config.align) != 'undefined' && config.align.length){
5792                 td.style += ' text-align:' + config.align + ';';
5793             }
5794             
5795             if(typeof(config.width) != 'undefined'){
5796                 td.style += ' width:' +  config.width + 'px;';
5797             }
5798             
5799             if(typeof(config.cursor) != 'undefined'){
5800                 td.style += ' cursor:' +  config.cursor + ';';
5801             }
5802              
5803             row.cn.push(td);
5804            
5805         }
5806         
5807         row.cellObjects = cellObjects;
5808         
5809         return row;
5810           
5811     },
5812     
5813     
5814     
5815     onBeforeLoad : function()
5816     {
5817         //Roo.log('ds onBeforeLoad');
5818         
5819         //this.clear();
5820         
5821         //if(this.loadMask){
5822         //    this.maskEl.show();
5823         //}
5824     },
5825      /**
5826      * Remove all rows
5827      */
5828     clear : function()
5829     {
5830         this.el.select('tbody', true).first().dom.innerHTML = '';
5831     },
5832     /**
5833      * Show or hide a row.
5834      * @param {Number} rowIndex to show or hide
5835      * @param {Boolean} state hide
5836      */
5837     setRowVisibility : function(rowIndex, state)
5838     {
5839         var bt = this.mainBody.dom;
5840         
5841         var rows = this.el.select('tbody > tr', true).elements;
5842         
5843         if(typeof(rows[rowIndex]) == 'undefined'){
5844             return;
5845         }
5846         rows[rowIndex].dom.style.display = state ? '' : 'none';
5847     },
5848     
5849     
5850     getSelectionModel : function(){
5851         if(!this.selModel){
5852             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5853         }
5854         return this.selModel;
5855     },
5856     /*
5857      * Render the Roo.bootstrap object from renderder
5858      */
5859     renderCellObject : function(r)
5860     {
5861         var _this = this;
5862         
5863         var t = r.cfg.render(r.container);
5864         
5865         if(r.cfg.cn){
5866             Roo.each(r.cfg.cn, function(c){
5867                 var child = {
5868                     container: t.getChildContainer(),
5869                     cfg: c
5870                 }
5871                 _this.renderCellObject(child);
5872             })
5873         }
5874     },
5875     
5876     getRowIndex : function(row)
5877     {
5878         var rowIndex = -1;
5879         
5880         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5881             if(el != row){
5882                 return;
5883             }
5884             
5885             rowIndex = index;
5886         });
5887         
5888         return rowIndex;
5889     }
5890    
5891 });
5892
5893  
5894
5895  /*
5896  * - LGPL
5897  *
5898  * table cell
5899  * 
5900  */
5901
5902 /**
5903  * @class Roo.bootstrap.TableCell
5904  * @extends Roo.bootstrap.Component
5905  * Bootstrap TableCell class
5906  * @cfg {String} html cell contain text
5907  * @cfg {String} cls cell class
5908  * @cfg {String} tag cell tag (td|th) default td
5909  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5910  * @cfg {String} align Aligns the content in a cell
5911  * @cfg {String} axis Categorizes cells
5912  * @cfg {String} bgcolor Specifies the background color of a cell
5913  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5914  * @cfg {Number} colspan Specifies the number of columns a cell should span
5915  * @cfg {String} headers Specifies one or more header cells a cell is related to
5916  * @cfg {Number} height Sets the height of a cell
5917  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5918  * @cfg {Number} rowspan Sets the number of rows a cell should span
5919  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5920  * @cfg {String} valign Vertical aligns the content in a cell
5921  * @cfg {Number} width Specifies the width of a cell
5922  * 
5923  * @constructor
5924  * Create a new TableCell
5925  * @param {Object} config The config object
5926  */
5927
5928 Roo.bootstrap.TableCell = function(config){
5929     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5930 };
5931
5932 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
5933     
5934     html: false,
5935     cls: false,
5936     tag: false,
5937     abbr: false,
5938     align: false,
5939     axis: false,
5940     bgcolor: false,
5941     charoff: false,
5942     colspan: false,
5943     headers: false,
5944     height: false,
5945     nowrap: false,
5946     rowspan: false,
5947     scope: false,
5948     valign: false,
5949     width: false,
5950     
5951     
5952     getAutoCreate : function(){
5953         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5954         
5955         cfg = {
5956             tag: 'td'
5957         }
5958         
5959         if(this.tag){
5960             cfg.tag = this.tag;
5961         }
5962         
5963         if (this.html) {
5964             cfg.html=this.html
5965         }
5966         if (this.cls) {
5967             cfg.cls=this.cls
5968         }
5969         if (this.abbr) {
5970             cfg.abbr=this.abbr
5971         }
5972         if (this.align) {
5973             cfg.align=this.align
5974         }
5975         if (this.axis) {
5976             cfg.axis=this.axis
5977         }
5978         if (this.bgcolor) {
5979             cfg.bgcolor=this.bgcolor
5980         }
5981         if (this.charoff) {
5982             cfg.charoff=this.charoff
5983         }
5984         if (this.colspan) {
5985             cfg.colspan=this.colspan
5986         }
5987         if (this.headers) {
5988             cfg.headers=this.headers
5989         }
5990         if (this.height) {
5991             cfg.height=this.height
5992         }
5993         if (this.nowrap) {
5994             cfg.nowrap=this.nowrap
5995         }
5996         if (this.rowspan) {
5997             cfg.rowspan=this.rowspan
5998         }
5999         if (this.scope) {
6000             cfg.scope=this.scope
6001         }
6002         if (this.valign) {
6003             cfg.valign=this.valign
6004         }
6005         if (this.width) {
6006             cfg.width=this.width
6007         }
6008         
6009         
6010         return cfg;
6011     }
6012    
6013 });
6014
6015  
6016
6017  /*
6018  * - LGPL
6019  *
6020  * table row
6021  * 
6022  */
6023
6024 /**
6025  * @class Roo.bootstrap.TableRow
6026  * @extends Roo.bootstrap.Component
6027  * Bootstrap TableRow class
6028  * @cfg {String} cls row class
6029  * @cfg {String} align Aligns the content in a table row
6030  * @cfg {String} bgcolor Specifies a background color for a table row
6031  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6032  * @cfg {String} valign Vertical aligns the content in a table row
6033  * 
6034  * @constructor
6035  * Create a new TableRow
6036  * @param {Object} config The config object
6037  */
6038
6039 Roo.bootstrap.TableRow = function(config){
6040     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6041 };
6042
6043 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
6044     
6045     cls: false,
6046     align: false,
6047     bgcolor: false,
6048     charoff: false,
6049     valign: false,
6050     
6051     getAutoCreate : function(){
6052         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6053         
6054         cfg = {
6055             tag: 'tr'
6056         }
6057             
6058         if(this.cls){
6059             cfg.cls = this.cls;
6060         }
6061         if(this.align){
6062             cfg.align = this.align;
6063         }
6064         if(this.bgcolor){
6065             cfg.bgcolor = this.bgcolor;
6066         }
6067         if(this.charoff){
6068             cfg.charoff = this.charoff;
6069         }
6070         if(this.valign){
6071             cfg.valign = this.valign;
6072         }
6073         
6074         return cfg;
6075     }
6076    
6077 });
6078
6079  
6080
6081  /*
6082  * - LGPL
6083  *
6084  * table body
6085  * 
6086  */
6087
6088 /**
6089  * @class Roo.bootstrap.TableBody
6090  * @extends Roo.bootstrap.Component
6091  * Bootstrap TableBody class
6092  * @cfg {String} cls element class
6093  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6094  * @cfg {String} align Aligns the content inside the element
6095  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6096  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6097  * 
6098  * @constructor
6099  * Create a new TableBody
6100  * @param {Object} config The config object
6101  */
6102
6103 Roo.bootstrap.TableBody = function(config){
6104     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6105 };
6106
6107 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
6108     
6109     cls: false,
6110     tag: false,
6111     align: false,
6112     charoff: false,
6113     valign: false,
6114     
6115     getAutoCreate : function(){
6116         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6117         
6118         cfg = {
6119             tag: 'tbody'
6120         }
6121             
6122         if (this.cls) {
6123             cfg.cls=this.cls
6124         }
6125         if(this.tag){
6126             cfg.tag = this.tag;
6127         }
6128         
6129         if(this.align){
6130             cfg.align = this.align;
6131         }
6132         if(this.charoff){
6133             cfg.charoff = this.charoff;
6134         }
6135         if(this.valign){
6136             cfg.valign = this.valign;
6137         }
6138         
6139         return cfg;
6140     }
6141     
6142     
6143 //    initEvents : function()
6144 //    {
6145 //        
6146 //        if(!this.store){
6147 //            return;
6148 //        }
6149 //        
6150 //        this.store = Roo.factory(this.store, Roo.data);
6151 //        this.store.on('load', this.onLoad, this);
6152 //        
6153 //        this.store.load();
6154 //        
6155 //    },
6156 //    
6157 //    onLoad: function () 
6158 //    {   
6159 //        this.fireEvent('load', this);
6160 //    }
6161 //    
6162 //   
6163 });
6164
6165  
6166
6167  /*
6168  * Based on:
6169  * Ext JS Library 1.1.1
6170  * Copyright(c) 2006-2007, Ext JS, LLC.
6171  *
6172  * Originally Released Under LGPL - original licence link has changed is not relivant.
6173  *
6174  * Fork - LGPL
6175  * <script type="text/javascript">
6176  */
6177
6178 // as we use this in bootstrap.
6179 Roo.namespace('Roo.form');
6180  /**
6181  * @class Roo.form.Action
6182  * Internal Class used to handle form actions
6183  * @constructor
6184  * @param {Roo.form.BasicForm} el The form element or its id
6185  * @param {Object} config Configuration options
6186  */
6187
6188  
6189  
6190 // define the action interface
6191 Roo.form.Action = function(form, options){
6192     this.form = form;
6193     this.options = options || {};
6194 };
6195 /**
6196  * Client Validation Failed
6197  * @const 
6198  */
6199 Roo.form.Action.CLIENT_INVALID = 'client';
6200 /**
6201  * Server Validation Failed
6202  * @const 
6203  */
6204 Roo.form.Action.SERVER_INVALID = 'server';
6205  /**
6206  * Connect to Server Failed
6207  * @const 
6208  */
6209 Roo.form.Action.CONNECT_FAILURE = 'connect';
6210 /**
6211  * Reading Data from Server Failed
6212  * @const 
6213  */
6214 Roo.form.Action.LOAD_FAILURE = 'load';
6215
6216 Roo.form.Action.prototype = {
6217     type : 'default',
6218     failureType : undefined,
6219     response : undefined,
6220     result : undefined,
6221
6222     // interface method
6223     run : function(options){
6224
6225     },
6226
6227     // interface method
6228     success : function(response){
6229
6230     },
6231
6232     // interface method
6233     handleResponse : function(response){
6234
6235     },
6236
6237     // default connection failure
6238     failure : function(response){
6239         
6240         this.response = response;
6241         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6242         this.form.afterAction(this, false);
6243     },
6244
6245     processResponse : function(response){
6246         this.response = response;
6247         if(!response.responseText){
6248             return true;
6249         }
6250         this.result = this.handleResponse(response);
6251         return this.result;
6252     },
6253
6254     // utility functions used internally
6255     getUrl : function(appendParams){
6256         var url = this.options.url || this.form.url || this.form.el.dom.action;
6257         if(appendParams){
6258             var p = this.getParams();
6259             if(p){
6260                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6261             }
6262         }
6263         return url;
6264     },
6265
6266     getMethod : function(){
6267         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6268     },
6269
6270     getParams : function(){
6271         var bp = this.form.baseParams;
6272         var p = this.options.params;
6273         if(p){
6274             if(typeof p == "object"){
6275                 p = Roo.urlEncode(Roo.applyIf(p, bp));
6276             }else if(typeof p == 'string' && bp){
6277                 p += '&' + Roo.urlEncode(bp);
6278             }
6279         }else if(bp){
6280             p = Roo.urlEncode(bp);
6281         }
6282         return p;
6283     },
6284
6285     createCallback : function(){
6286         return {
6287             success: this.success,
6288             failure: this.failure,
6289             scope: this,
6290             timeout: (this.form.timeout*1000),
6291             upload: this.form.fileUpload ? this.success : undefined
6292         };
6293     }
6294 };
6295
6296 Roo.form.Action.Submit = function(form, options){
6297     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6298 };
6299
6300 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6301     type : 'submit',
6302
6303     haveProgress : false,
6304     uploadComplete : false,
6305     
6306     // uploadProgress indicator.
6307     uploadProgress : function()
6308     {
6309         if (!this.form.progressUrl) {
6310             return;
6311         }
6312         
6313         if (!this.haveProgress) {
6314             Roo.MessageBox.progress("Uploading", "Uploading");
6315         }
6316         if (this.uploadComplete) {
6317            Roo.MessageBox.hide();
6318            return;
6319         }
6320         
6321         this.haveProgress = true;
6322    
6323         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6324         
6325         var c = new Roo.data.Connection();
6326         c.request({
6327             url : this.form.progressUrl,
6328             params: {
6329                 id : uid
6330             },
6331             method: 'GET',
6332             success : function(req){
6333                //console.log(data);
6334                 var rdata = false;
6335                 var edata;
6336                 try  {
6337                    rdata = Roo.decode(req.responseText)
6338                 } catch (e) {
6339                     Roo.log("Invalid data from server..");
6340                     Roo.log(edata);
6341                     return;
6342                 }
6343                 if (!rdata || !rdata.success) {
6344                     Roo.log(rdata);
6345                     Roo.MessageBox.alert(Roo.encode(rdata));
6346                     return;
6347                 }
6348                 var data = rdata.data;
6349                 
6350                 if (this.uploadComplete) {
6351                    Roo.MessageBox.hide();
6352                    return;
6353                 }
6354                    
6355                 if (data){
6356                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6357                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6358                     );
6359                 }
6360                 this.uploadProgress.defer(2000,this);
6361             },
6362        
6363             failure: function(data) {
6364                 Roo.log('progress url failed ');
6365                 Roo.log(data);
6366             },
6367             scope : this
6368         });
6369            
6370     },
6371     
6372     
6373     run : function()
6374     {
6375         // run get Values on the form, so it syncs any secondary forms.
6376         this.form.getValues();
6377         
6378         var o = this.options;
6379         var method = this.getMethod();
6380         var isPost = method == 'POST';
6381         if(o.clientValidation === false || this.form.isValid()){
6382             
6383             if (this.form.progressUrl) {
6384                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6385                     (new Date() * 1) + '' + Math.random());
6386                     
6387             } 
6388             
6389             
6390             Roo.Ajax.request(Roo.apply(this.createCallback(), {
6391                 form:this.form.el.dom,
6392                 url:this.getUrl(!isPost),
6393                 method: method,
6394                 params:isPost ? this.getParams() : null,
6395                 isUpload: this.form.fileUpload
6396             }));
6397             
6398             this.uploadProgress();
6399
6400         }else if (o.clientValidation !== false){ // client validation failed
6401             this.failureType = Roo.form.Action.CLIENT_INVALID;
6402             this.form.afterAction(this, false);
6403         }
6404     },
6405
6406     success : function(response)
6407     {
6408         this.uploadComplete= true;
6409         if (this.haveProgress) {
6410             Roo.MessageBox.hide();
6411         }
6412         
6413         
6414         var result = this.processResponse(response);
6415         if(result === true || result.success){
6416             this.form.afterAction(this, true);
6417             return;
6418         }
6419         if(result.errors){
6420             this.form.markInvalid(result.errors);
6421             this.failureType = Roo.form.Action.SERVER_INVALID;
6422         }
6423         this.form.afterAction(this, false);
6424     },
6425     failure : function(response)
6426     {
6427         this.uploadComplete= true;
6428         if (this.haveProgress) {
6429             Roo.MessageBox.hide();
6430         }
6431         
6432         this.response = response;
6433         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6434         this.form.afterAction(this, false);
6435     },
6436     
6437     handleResponse : function(response){
6438         if(this.form.errorReader){
6439             var rs = this.form.errorReader.read(response);
6440             var errors = [];
6441             if(rs.records){
6442                 for(var i = 0, len = rs.records.length; i < len; i++) {
6443                     var r = rs.records[i];
6444                     errors[i] = r.data;
6445                 }
6446             }
6447             if(errors.length < 1){
6448                 errors = null;
6449             }
6450             return {
6451                 success : rs.success,
6452                 errors : errors
6453             };
6454         }
6455         var ret = false;
6456         try {
6457             ret = Roo.decode(response.responseText);
6458         } catch (e) {
6459             ret = {
6460                 success: false,
6461                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6462                 errors : []
6463             };
6464         }
6465         return ret;
6466         
6467     }
6468 });
6469
6470
6471 Roo.form.Action.Load = function(form, options){
6472     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6473     this.reader = this.form.reader;
6474 };
6475
6476 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6477     type : 'load',
6478
6479     run : function(){
6480         
6481         Roo.Ajax.request(Roo.apply(
6482                 this.createCallback(), {
6483                     method:this.getMethod(),
6484                     url:this.getUrl(false),
6485                     params:this.getParams()
6486         }));
6487     },
6488
6489     success : function(response){
6490         
6491         var result = this.processResponse(response);
6492         if(result === true || !result.success || !result.data){
6493             this.failureType = Roo.form.Action.LOAD_FAILURE;
6494             this.form.afterAction(this, false);
6495             return;
6496         }
6497         this.form.clearInvalid();
6498         this.form.setValues(result.data);
6499         this.form.afterAction(this, true);
6500     },
6501
6502     handleResponse : function(response){
6503         if(this.form.reader){
6504             var rs = this.form.reader.read(response);
6505             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6506             return {
6507                 success : rs.success,
6508                 data : data
6509             };
6510         }
6511         return Roo.decode(response.responseText);
6512     }
6513 });
6514
6515 Roo.form.Action.ACTION_TYPES = {
6516     'load' : Roo.form.Action.Load,
6517     'submit' : Roo.form.Action.Submit
6518 };/*
6519  * - LGPL
6520  *
6521  * form
6522  * 
6523  */
6524
6525 /**
6526  * @class Roo.bootstrap.Form
6527  * @extends Roo.bootstrap.Component
6528  * Bootstrap Form class
6529  * @cfg {String} method  GET | POST (default POST)
6530  * @cfg {String} labelAlign top | left (default top)
6531  * @cfg {String} align left  | right - for navbars
6532  * @cfg {Boolean} loadMask load mask when submit (default true)
6533
6534  * 
6535  * @constructor
6536  * Create a new Form
6537  * @param {Object} config The config object
6538  */
6539
6540
6541 Roo.bootstrap.Form = function(config){
6542     Roo.bootstrap.Form.superclass.constructor.call(this, config);
6543     this.addEvents({
6544         /**
6545          * @event clientvalidation
6546          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6547          * @param {Form} this
6548          * @param {Boolean} valid true if the form has passed client-side validation
6549          */
6550         clientvalidation: true,
6551         /**
6552          * @event beforeaction
6553          * Fires before any action is performed. Return false to cancel the action.
6554          * @param {Form} this
6555          * @param {Action} action The action to be performed
6556          */
6557         beforeaction: true,
6558         /**
6559          * @event actionfailed
6560          * Fires when an action fails.
6561          * @param {Form} this
6562          * @param {Action} action The action that failed
6563          */
6564         actionfailed : true,
6565         /**
6566          * @event actioncomplete
6567          * Fires when an action is completed.
6568          * @param {Form} this
6569          * @param {Action} action The action that completed
6570          */
6571         actioncomplete : true
6572     });
6573     
6574 };
6575
6576 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
6577       
6578      /**
6579      * @cfg {String} method
6580      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6581      */
6582     method : 'POST',
6583     /**
6584      * @cfg {String} url
6585      * The URL to use for form actions if one isn't supplied in the action options.
6586      */
6587     /**
6588      * @cfg {Boolean} fileUpload
6589      * Set to true if this form is a file upload.
6590      */
6591      
6592     /**
6593      * @cfg {Object} baseParams
6594      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6595      */
6596       
6597     /**
6598      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6599      */
6600     timeout: 30,
6601     /**
6602      * @cfg {Sting} align (left|right) for navbar forms
6603      */
6604     align : 'left',
6605
6606     // private
6607     activeAction : null,
6608  
6609     /**
6610      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6611      * element by passing it or its id or mask the form itself by passing in true.
6612      * @type Mixed
6613      */
6614     waitMsgTarget : false,
6615     
6616     loadMask : true,
6617     
6618     getAutoCreate : function(){
6619         
6620         var cfg = {
6621             tag: 'form',
6622             method : this.method || 'POST',
6623             id : this.id || Roo.id(),
6624             cls : ''
6625         }
6626         if (this.parent().xtype.match(/^Nav/)) {
6627             cfg.cls = 'navbar-form navbar-' + this.align;
6628             
6629         }
6630         
6631         if (this.labelAlign == 'left' ) {
6632             cfg.cls += ' form-horizontal';
6633         }
6634         
6635         
6636         return cfg;
6637     },
6638     initEvents : function()
6639     {
6640         this.el.on('submit', this.onSubmit, this);
6641         // this was added as random key presses on the form where triggering form submit.
6642         this.el.on('keypress', function(e) {
6643             if (e.getCharCode() != 13) {
6644                 return true;
6645             }
6646             // we might need to allow it for textareas.. and some other items.
6647             // check e.getTarget().
6648             
6649             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6650                 return true;
6651             }
6652         
6653             Roo.log("keypress blocked");
6654             
6655             e.preventDefault();
6656             return false;
6657         });
6658         
6659     },
6660     // private
6661     onSubmit : function(e){
6662         e.stopEvent();
6663     },
6664     
6665      /**
6666      * Returns true if client-side validation on the form is successful.
6667      * @return Boolean
6668      */
6669     isValid : function(){
6670         var items = this.getItems();
6671         var valid = true;
6672         items.each(function(f){
6673            if(!f.validate()){
6674                valid = false;
6675                
6676            }
6677         });
6678         return valid;
6679     },
6680     /**
6681      * Returns true if any fields in this form have changed since their original load.
6682      * @return Boolean
6683      */
6684     isDirty : function(){
6685         var dirty = false;
6686         var items = this.getItems();
6687         items.each(function(f){
6688            if(f.isDirty()){
6689                dirty = true;
6690                return false;
6691            }
6692            return true;
6693         });
6694         return dirty;
6695     },
6696      /**
6697      * Performs a predefined action (submit or load) or custom actions you define on this form.
6698      * @param {String} actionName The name of the action type
6699      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
6700      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6701      * accept other config options):
6702      * <pre>
6703 Property          Type             Description
6704 ----------------  ---------------  ----------------------------------------------------------------------------------
6705 url               String           The url for the action (defaults to the form's url)
6706 method            String           The form method to use (defaults to the form's method, or POST if not defined)
6707 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
6708 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
6709                                    validate the form on the client (defaults to false)
6710      * </pre>
6711      * @return {BasicForm} this
6712      */
6713     doAction : function(action, options){
6714         if(typeof action == 'string'){
6715             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6716         }
6717         if(this.fireEvent('beforeaction', this, action) !== false){
6718             this.beforeAction(action);
6719             action.run.defer(100, action);
6720         }
6721         return this;
6722     },
6723     
6724     // private
6725     beforeAction : function(action){
6726         var o = action.options;
6727         
6728         if(this.loadMask){
6729             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6730         }
6731         // not really supported yet.. ??
6732         
6733         //if(this.waitMsgTarget === true){
6734         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6735         //}else if(this.waitMsgTarget){
6736         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6737         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6738         //}else {
6739         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6740        // }
6741          
6742     },
6743
6744     // private
6745     afterAction : function(action, success){
6746         this.activeAction = null;
6747         var o = action.options;
6748         
6749         //if(this.waitMsgTarget === true){
6750             this.el.unmask();
6751         //}else if(this.waitMsgTarget){
6752         //    this.waitMsgTarget.unmask();
6753         //}else{
6754         //    Roo.MessageBox.updateProgress(1);
6755         //    Roo.MessageBox.hide();
6756        // }
6757         // 
6758         if(success){
6759             if(o.reset){
6760                 this.reset();
6761             }
6762             Roo.callback(o.success, o.scope, [this, action]);
6763             this.fireEvent('actioncomplete', this, action);
6764             
6765         }else{
6766             
6767             // failure condition..
6768             // we have a scenario where updates need confirming.
6769             // eg. if a locking scenario exists..
6770             // we look for { errors : { needs_confirm : true }} in the response.
6771             if (
6772                 (typeof(action.result) != 'undefined')  &&
6773                 (typeof(action.result.errors) != 'undefined')  &&
6774                 (typeof(action.result.errors.needs_confirm) != 'undefined')
6775            ){
6776                 var _t = this;
6777                 Roo.log("not supported yet");
6778                  /*
6779                 
6780                 Roo.MessageBox.confirm(
6781                     "Change requires confirmation",
6782                     action.result.errorMsg,
6783                     function(r) {
6784                         if (r != 'yes') {
6785                             return;
6786                         }
6787                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
6788                     }
6789                     
6790                 );
6791                 */
6792                 
6793                 
6794                 return;
6795             }
6796             
6797             Roo.callback(o.failure, o.scope, [this, action]);
6798             // show an error message if no failed handler is set..
6799             if (!this.hasListener('actionfailed')) {
6800                 Roo.log("need to add dialog support");
6801                 /*
6802                 Roo.MessageBox.alert("Error",
6803                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6804                         action.result.errorMsg :
6805                         "Saving Failed, please check your entries or try again"
6806                 );
6807                 */
6808             }
6809             
6810             this.fireEvent('actionfailed', this, action);
6811         }
6812         
6813     },
6814     /**
6815      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6816      * @param {String} id The value to search for
6817      * @return Field
6818      */
6819     findField : function(id){
6820         var items = this.getItems();
6821         var field = items.get(id);
6822         if(!field){
6823              items.each(function(f){
6824                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6825                     field = f;
6826                     return false;
6827                 }
6828                 return true;
6829             });
6830         }
6831         return field || null;
6832     },
6833      /**
6834      * Mark fields in this form invalid in bulk.
6835      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6836      * @return {BasicForm} this
6837      */
6838     markInvalid : function(errors){
6839         if(errors instanceof Array){
6840             for(var i = 0, len = errors.length; i < len; i++){
6841                 var fieldError = errors[i];
6842                 var f = this.findField(fieldError.id);
6843                 if(f){
6844                     f.markInvalid(fieldError.msg);
6845                 }
6846             }
6847         }else{
6848             var field, id;
6849             for(id in errors){
6850                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6851                     field.markInvalid(errors[id]);
6852                 }
6853             }
6854         }
6855         //Roo.each(this.childForms || [], function (f) {
6856         //    f.markInvalid(errors);
6857         //});
6858         
6859         return this;
6860     },
6861
6862     /**
6863      * Set values for fields in this form in bulk.
6864      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6865      * @return {BasicForm} this
6866      */
6867     setValues : function(values){
6868         if(values instanceof Array){ // array of objects
6869             for(var i = 0, len = values.length; i < len; i++){
6870                 var v = values[i];
6871                 var f = this.findField(v.id);
6872                 if(f){
6873                     f.setValue(v.value);
6874                     if(this.trackResetOnLoad){
6875                         f.originalValue = f.getValue();
6876                     }
6877                 }
6878             }
6879         }else{ // object hash
6880             var field, id;
6881             for(id in values){
6882                 if(typeof values[id] != 'function' && (field = this.findField(id))){
6883                     
6884                     if (field.setFromData && 
6885                         field.valueField && 
6886                         field.displayField &&
6887                         // combos' with local stores can 
6888                         // be queried via setValue()
6889                         // to set their value..
6890                         (field.store && !field.store.isLocal)
6891                         ) {
6892                         // it's a combo
6893                         var sd = { };
6894                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6895                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6896                         field.setFromData(sd);
6897                         
6898                     } else {
6899                         field.setValue(values[id]);
6900                     }
6901                     
6902                     
6903                     if(this.trackResetOnLoad){
6904                         field.originalValue = field.getValue();
6905                     }
6906                 }
6907             }
6908         }
6909          
6910         //Roo.each(this.childForms || [], function (f) {
6911         //    f.setValues(values);
6912         //});
6913                 
6914         return this;
6915     },
6916
6917     /**
6918      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6919      * they are returned as an array.
6920      * @param {Boolean} asString
6921      * @return {Object}
6922      */
6923     getValues : function(asString){
6924         //if (this.childForms) {
6925             // copy values from the child forms
6926         //    Roo.each(this.childForms, function (f) {
6927         //        this.setValues(f.getValues());
6928         //    }, this);
6929         //}
6930         
6931         
6932         
6933         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6934         if(asString === true){
6935             return fs;
6936         }
6937         return Roo.urlDecode(fs);
6938     },
6939     
6940     /**
6941      * Returns the fields in this form as an object with key/value pairs. 
6942      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6943      * @return {Object}
6944      */
6945     getFieldValues : function(with_hidden)
6946     {
6947         var items = this.getItems();
6948         var ret = {};
6949         items.each(function(f){
6950             if (!f.getName()) {
6951                 return;
6952             }
6953             var v = f.getValue();
6954             if (f.inputType =='radio') {
6955                 if (typeof(ret[f.getName()]) == 'undefined') {
6956                     ret[f.getName()] = ''; // empty..
6957                 }
6958                 
6959                 if (!f.el.dom.checked) {
6960                     return;
6961                     
6962                 }
6963                 v = f.el.dom.value;
6964                 
6965             }
6966             
6967             // not sure if this supported any more..
6968             if ((typeof(v) == 'object') && f.getRawValue) {
6969                 v = f.getRawValue() ; // dates..
6970             }
6971             // combo boxes where name != hiddenName...
6972             if (f.name != f.getName()) {
6973                 ret[f.name] = f.getRawValue();
6974             }
6975             ret[f.getName()] = v;
6976         });
6977         
6978         return ret;
6979     },
6980
6981     /**
6982      * Clears all invalid messages in this form.
6983      * @return {BasicForm} this
6984      */
6985     clearInvalid : function(){
6986         var items = this.getItems();
6987         
6988         items.each(function(f){
6989            f.clearInvalid();
6990         });
6991         
6992         
6993         
6994         return this;
6995     },
6996
6997     /**
6998      * Resets this form.
6999      * @return {BasicForm} this
7000      */
7001     reset : function(){
7002         var items = this.getItems();
7003         items.each(function(f){
7004             f.reset();
7005         });
7006         
7007         Roo.each(this.childForms || [], function (f) {
7008             f.reset();
7009         });
7010        
7011         
7012         return this;
7013     },
7014     getItems : function()
7015     {
7016         var r=new Roo.util.MixedCollection(false, function(o){
7017             return o.id || (o.id = Roo.id());
7018         });
7019         var iter = function(el) {
7020             if (el.inputEl) {
7021                 r.add(el);
7022             }
7023             if (!el.items) {
7024                 return;
7025             }
7026             Roo.each(el.items,function(e) {
7027                 iter(e);
7028             });
7029             
7030             
7031         };
7032         
7033         iter(this);
7034         return r;
7035         
7036         
7037         
7038         
7039     }
7040     
7041 });
7042
7043  
7044 /*
7045  * Based on:
7046  * Ext JS Library 1.1.1
7047  * Copyright(c) 2006-2007, Ext JS, LLC.
7048  *
7049  * Originally Released Under LGPL - original licence link has changed is not relivant.
7050  *
7051  * Fork - LGPL
7052  * <script type="text/javascript">
7053  */
7054 /**
7055  * @class Roo.form.VTypes
7056  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7057  * @singleton
7058  */
7059 Roo.form.VTypes = function(){
7060     // closure these in so they are only created once.
7061     var alpha = /^[a-zA-Z_]+$/;
7062     var alphanum = /^[a-zA-Z0-9_]+$/;
7063     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7064     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7065
7066     // All these messages and functions are configurable
7067     return {
7068         /**
7069          * The function used to validate email addresses
7070          * @param {String} value The email address
7071          */
7072         'email' : function(v){
7073             return email.test(v);
7074         },
7075         /**
7076          * The error text to display when the email validation function returns false
7077          * @type String
7078          */
7079         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7080         /**
7081          * The keystroke filter mask to be applied on email input
7082          * @type RegExp
7083          */
7084         'emailMask' : /[a-z0-9_\.\-@]/i,
7085
7086         /**
7087          * The function used to validate URLs
7088          * @param {String} value The URL
7089          */
7090         'url' : function(v){
7091             return url.test(v);
7092         },
7093         /**
7094          * The error text to display when the url validation function returns false
7095          * @type String
7096          */
7097         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7098         
7099         /**
7100          * The function used to validate alpha values
7101          * @param {String} value The value
7102          */
7103         'alpha' : function(v){
7104             return alpha.test(v);
7105         },
7106         /**
7107          * The error text to display when the alpha validation function returns false
7108          * @type String
7109          */
7110         'alphaText' : 'This field should only contain letters and _',
7111         /**
7112          * The keystroke filter mask to be applied on alpha input
7113          * @type RegExp
7114          */
7115         'alphaMask' : /[a-z_]/i,
7116
7117         /**
7118          * The function used to validate alphanumeric values
7119          * @param {String} value The value
7120          */
7121         'alphanum' : function(v){
7122             return alphanum.test(v);
7123         },
7124         /**
7125          * The error text to display when the alphanumeric validation function returns false
7126          * @type String
7127          */
7128         'alphanumText' : 'This field should only contain letters, numbers and _',
7129         /**
7130          * The keystroke filter mask to be applied on alphanumeric input
7131          * @type RegExp
7132          */
7133         'alphanumMask' : /[a-z0-9_]/i
7134     };
7135 }();/*
7136  * - LGPL
7137  *
7138  * Input
7139  * 
7140  */
7141
7142 /**
7143  * @class Roo.bootstrap.Input
7144  * @extends Roo.bootstrap.Component
7145  * Bootstrap Input class
7146  * @cfg {Boolean} disabled is it disabled
7147  * @cfg {String} fieldLabel - the label associated
7148  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7149  * @cfg {String} name name of the input
7150  * @cfg {string} fieldLabel - the label associated
7151  * @cfg {string}  inputType - input / file submit ...
7152  * @cfg {string} placeholder - placeholder to put in text.
7153  * @cfg {string}  before - input group add on before
7154  * @cfg {string} after - input group add on after
7155  * @cfg {string} size - (lg|sm) or leave empty..
7156  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7157  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7158  * @cfg {Number} md colspan out of 12 for computer-sized screens
7159  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7160  * @cfg {string} value default value of the input
7161  * @cfg {Number} labelWidth set the width of label (0-12)
7162  * @cfg {String} labelAlign (top|left)
7163  * @cfg {Boolean} readOnly Specifies that the field should be read-only
7164  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7165
7166  * @cfg {String} align (left|center|right) Default left
7167  * 
7168  * 
7169  * 
7170  * @constructor
7171  * Create a new Input
7172  * @param {Object} config The config object
7173  */
7174
7175 Roo.bootstrap.Input = function(config){
7176     Roo.bootstrap.Input.superclass.constructor.call(this, config);
7177    
7178         this.addEvents({
7179             /**
7180              * @event focus
7181              * Fires when this field receives input focus.
7182              * @param {Roo.form.Field} this
7183              */
7184             focus : true,
7185             /**
7186              * @event blur
7187              * Fires when this field loses input focus.
7188              * @param {Roo.form.Field} this
7189              */
7190             blur : true,
7191             /**
7192              * @event specialkey
7193              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
7194              * {@link Roo.EventObject#getKey} to determine which key was pressed.
7195              * @param {Roo.form.Field} this
7196              * @param {Roo.EventObject} e The event object
7197              */
7198             specialkey : true,
7199             /**
7200              * @event change
7201              * Fires just before the field blurs if the field value has changed.
7202              * @param {Roo.form.Field} this
7203              * @param {Mixed} newValue The new value
7204              * @param {Mixed} oldValue The original value
7205              */
7206             change : true,
7207             /**
7208              * @event invalid
7209              * Fires after the field has been marked as invalid.
7210              * @param {Roo.form.Field} this
7211              * @param {String} msg The validation message
7212              */
7213             invalid : true,
7214             /**
7215              * @event valid
7216              * Fires after the field has been validated with no errors.
7217              * @param {Roo.form.Field} this
7218              */
7219             valid : true,
7220              /**
7221              * @event keyup
7222              * Fires after the key up
7223              * @param {Roo.form.Field} this
7224              * @param {Roo.EventObject}  e The event Object
7225              */
7226             keyup : true
7227         });
7228 };
7229
7230 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
7231      /**
7232      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7233       automatic validation (defaults to "keyup").
7234      */
7235     validationEvent : "keyup",
7236      /**
7237      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7238      */
7239     validateOnBlur : true,
7240     /**
7241      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7242      */
7243     validationDelay : 250,
7244      /**
7245      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7246      */
7247     focusClass : "x-form-focus",  // not needed???
7248     
7249        
7250     /**
7251      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7252      */
7253     invalidClass : "has-warning",
7254     
7255     /**
7256      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7257      */
7258     validClass : "has-success",
7259     
7260     /**
7261      * @cfg {Boolean} hasFeedback (true|false) default true
7262      */
7263     hasFeedback : true,
7264     
7265     /**
7266      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7267      */
7268     invalidFeedbackClass : "glyphicon-warning-sign",
7269     
7270     /**
7271      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7272      */
7273     validFeedbackClass : "glyphicon-ok",
7274     
7275     /**
7276      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7277      */
7278     selectOnFocus : false,
7279     
7280      /**
7281      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7282      */
7283     maskRe : null,
7284        /**
7285      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7286      */
7287     vtype : null,
7288     
7289       /**
7290      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7291      */
7292     disableKeyFilter : false,
7293     
7294        /**
7295      * @cfg {Boolean} disabled True to disable the field (defaults to false).
7296      */
7297     disabled : false,
7298      /**
7299      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7300      */
7301     allowBlank : true,
7302     /**
7303      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7304      */
7305     blankText : "This field is required",
7306     
7307      /**
7308      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7309      */
7310     minLength : 0,
7311     /**
7312      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7313      */
7314     maxLength : Number.MAX_VALUE,
7315     /**
7316      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7317      */
7318     minLengthText : "The minimum length for this field is {0}",
7319     /**
7320      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7321      */
7322     maxLengthText : "The maximum length for this field is {0}",
7323   
7324     
7325     /**
7326      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7327      * If available, this function will be called only after the basic validators all return true, and will be passed the
7328      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7329      */
7330     validator : null,
7331     /**
7332      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7333      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7334      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
7335      */
7336     regex : null,
7337     /**
7338      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7339      */
7340     regexText : "",
7341     
7342     autocomplete: false,
7343     
7344     
7345     fieldLabel : '',
7346     inputType : 'text',
7347     
7348     name : false,
7349     placeholder: false,
7350     before : false,
7351     after : false,
7352     size : false,
7353     hasFocus : false,
7354     preventMark: false,
7355     isFormField : true,
7356     value : '',
7357     labelWidth : 2,
7358     labelAlign : false,
7359     readOnly : false,
7360     align : false,
7361     formatedValue : false,
7362     
7363     parentLabelAlign : function()
7364     {
7365         var parent = this;
7366         while (parent.parent()) {
7367             parent = parent.parent();
7368             if (typeof(parent.labelAlign) !='undefined') {
7369                 return parent.labelAlign;
7370             }
7371         }
7372         return 'left';
7373         
7374     },
7375     
7376     getAutoCreate : function(){
7377         
7378         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7379         
7380         var id = Roo.id();
7381         
7382         var cfg = {};
7383         
7384         if(this.inputType != 'hidden'){
7385             cfg.cls = 'form-group' //input-group
7386         }
7387         
7388         var input =  {
7389             tag: 'input',
7390             id : id,
7391             type : this.inputType,
7392             value : this.value,
7393             cls : 'form-control',
7394             placeholder : this.placeholder || '',
7395             autocomplete : this.autocomplete || 'new-password'
7396         };
7397         
7398         
7399         if(this.align){
7400             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7401         }
7402         
7403         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7404             input.maxLength = this.maxLength;
7405         }
7406         
7407         if (this.disabled) {
7408             input.disabled=true;
7409         }
7410         
7411         if (this.readOnly) {
7412             input.readonly=true;
7413         }
7414         
7415         if (this.name) {
7416             input.name = this.name;
7417         }
7418         if (this.size) {
7419             input.cls += ' input-' + this.size;
7420         }
7421         var settings=this;
7422         ['xs','sm','md','lg'].map(function(size){
7423             if (settings[size]) {
7424                 cfg.cls += ' col-' + size + '-' + settings[size];
7425             }
7426         });
7427         
7428         var inputblock = input;
7429         
7430         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7431             
7432             var feedback = {
7433                 tag: 'span',
7434                 cls: 'glyphicon form-control-feedback'
7435             };
7436
7437             inputblock = {
7438                 cls : 'has-feedback',
7439                 cn :  [
7440                     input,
7441                     feedback
7442                 ] 
7443             };  
7444         }
7445          
7446 //        var inputblock = input;
7447         
7448         if (this.before || this.after) {
7449             
7450             inputblock = {
7451                 cls : 'input-group',
7452                 cn :  [] 
7453             };
7454             
7455             if (this.before && typeof(this.before) == 'string') {
7456                 
7457                 inputblock.cn.push({
7458                     tag :'span',
7459                     cls : 'roo-input-before input-group-addon',
7460                     html : this.before
7461                 });
7462             }
7463             if (this.before && typeof(this.before) == 'object') {
7464                 this.before = Roo.factory(this.before);
7465                 Roo.log(this.before);
7466                 inputblock.cn.push({
7467                     tag :'span',
7468                     cls : 'roo-input-before input-group-' +
7469                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7470                 });
7471             }
7472             
7473             inputblock.cn.push(input);
7474             
7475             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7476                 inputblock.cls += ' has-feedback';
7477                 inputblock.cn.push(feedback);
7478             }
7479             
7480             if (this.after && typeof(this.after) == 'string') {
7481                 inputblock.cn.push({
7482                     tag :'span',
7483                     cls : 'roo-input-after input-group-addon',
7484                     html : this.after
7485                 });
7486             }
7487             if (this.after && typeof(this.after) == 'object') {
7488                 this.after = Roo.factory(this.after);
7489                 Roo.log(this.after);
7490                 inputblock.cn.push({
7491                     tag :'span',
7492                     cls : 'roo-input-after input-group-' +
7493                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7494                 });
7495             }
7496         };
7497         
7498         if (align ==='left' && this.fieldLabel.length) {
7499                 Roo.log("left and has label");
7500                 cfg.cn = [
7501                     
7502                     {
7503                         tag: 'label',
7504                         'for' :  id,
7505                         cls : 'control-label col-sm-' + this.labelWidth,
7506                         html : this.fieldLabel
7507                         
7508                     },
7509                     {
7510                         cls : "col-sm-" + (12 - this.labelWidth), 
7511                         cn: [
7512                             inputblock
7513                         ]
7514                     }
7515                     
7516                 ];
7517         } else if ( this.fieldLabel.length) {
7518                 Roo.log(" label");
7519                  cfg.cn = [
7520                    
7521                     {
7522                         tag: 'label',
7523                         //cls : 'input-group-addon',
7524                         html : this.fieldLabel
7525                         
7526                     },
7527                     
7528                     inputblock
7529                     
7530                 ];
7531
7532         } else {
7533             
7534                 Roo.log(" no label && no align");
7535                 cfg.cn = [
7536                     
7537                         inputblock
7538                     
7539                 ];
7540                 
7541                 
7542         };
7543         Roo.log('input-parentType: ' + this.parentType);
7544         
7545         if (this.parentType === 'Navbar' &&  this.parent().bar) {
7546            cfg.cls += ' navbar-form';
7547            Roo.log(cfg);
7548         }
7549         
7550         return cfg;
7551         
7552     },
7553     /**
7554      * return the real input element.
7555      */
7556     inputEl: function ()
7557     {
7558         return this.el.select('input.form-control',true).first();
7559     },
7560     
7561     tooltipEl : function()
7562     {
7563         return this.inputEl();
7564     },
7565     
7566     setDisabled : function(v)
7567     {
7568         var i  = this.inputEl().dom;
7569         if (!v) {
7570             i.removeAttribute('disabled');
7571             return;
7572             
7573         }
7574         i.setAttribute('disabled','true');
7575     },
7576     initEvents : function()
7577     {
7578           
7579         this.inputEl().on("keydown" , this.fireKey,  this);
7580         this.inputEl().on("focus", this.onFocus,  this);
7581         this.inputEl().on("blur", this.onBlur,  this);
7582         
7583         this.inputEl().relayEvent('keyup', this);
7584
7585         // reference to original value for reset
7586         this.originalValue = this.getValue();
7587         //Roo.form.TextField.superclass.initEvents.call(this);
7588         if(this.validationEvent == 'keyup'){
7589             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7590             this.inputEl().on('keyup', this.filterValidation, this);
7591         }
7592         else if(this.validationEvent !== false){
7593             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7594         }
7595         
7596         if(this.selectOnFocus){
7597             this.on("focus", this.preFocus, this);
7598             
7599         }
7600         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7601             this.inputEl().on("keypress", this.filterKeys, this);
7602         }
7603        /* if(this.grow){
7604             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
7605             this.el.on("click", this.autoSize,  this);
7606         }
7607         */
7608         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7609             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7610         }
7611         
7612         if (typeof(this.before) == 'object') {
7613             this.before.render(this.el.select('.roo-input-before',true).first());
7614         }
7615         if (typeof(this.after) == 'object') {
7616             this.after.render(this.el.select('.roo-input-after',true).first());
7617         }
7618         
7619         
7620     },
7621     filterValidation : function(e){
7622         if(!e.isNavKeyPress()){
7623             this.validationTask.delay(this.validationDelay);
7624         }
7625     },
7626      /**
7627      * Validates the field value
7628      * @return {Boolean} True if the value is valid, else false
7629      */
7630     validate : function(){
7631         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7632         if(this.disabled || this.validateValue(this.getRawValue())){
7633             this.markValid();
7634             return true;
7635         }
7636         
7637         this.markInvalid();
7638         return false;
7639     },
7640     
7641     
7642     /**
7643      * Validates a value according to the field's validation rules and marks the field as invalid
7644      * if the validation fails
7645      * @param {Mixed} value The value to validate
7646      * @return {Boolean} True if the value is valid, else false
7647      */
7648     validateValue : function(value){
7649         if(value.length < 1)  { // if it's blank
7650             if(this.allowBlank){
7651                 return true;
7652             }
7653             return false;
7654         }
7655         
7656         if(value.length < this.minLength){
7657             return false;
7658         }
7659         if(value.length > this.maxLength){
7660             return false;
7661         }
7662         if(this.vtype){
7663             var vt = Roo.form.VTypes;
7664             if(!vt[this.vtype](value, this)){
7665                 return false;
7666             }
7667         }
7668         if(typeof this.validator == "function"){
7669             var msg = this.validator(value);
7670             if(msg !== true){
7671                 return false;
7672             }
7673         }
7674         
7675         if(this.regex && !this.regex.test(value)){
7676             return false;
7677         }
7678         
7679         return true;
7680     },
7681
7682     
7683     
7684      // private
7685     fireKey : function(e){
7686         //Roo.log('field ' + e.getKey());
7687         if(e.isNavKeyPress()){
7688             this.fireEvent("specialkey", this, e);
7689         }
7690     },
7691     focus : function (selectText){
7692         if(this.rendered){
7693             this.inputEl().focus();
7694             if(selectText === true){
7695                 this.inputEl().dom.select();
7696             }
7697         }
7698         return this;
7699     } ,
7700     
7701     onFocus : function(){
7702         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7703            // this.el.addClass(this.focusClass);
7704         }
7705         if(!this.hasFocus){
7706             this.hasFocus = true;
7707             this.startValue = this.getValue();
7708             this.fireEvent("focus", this);
7709         }
7710     },
7711     
7712     beforeBlur : Roo.emptyFn,
7713
7714     
7715     // private
7716     onBlur : function(){
7717         this.beforeBlur();
7718         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7719             //this.el.removeClass(this.focusClass);
7720         }
7721         this.hasFocus = false;
7722         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7723             this.validate();
7724         }
7725         var v = this.getValue();
7726         if(String(v) !== String(this.startValue)){
7727             this.fireEvent('change', this, v, this.startValue);
7728         }
7729         this.fireEvent("blur", this);
7730     },
7731     
7732     /**
7733      * Resets the current field value to the originally loaded value and clears any validation messages
7734      */
7735     reset : function(){
7736         this.setValue(this.originalValue);
7737         this.validate();
7738     },
7739      /**
7740      * Returns the name of the field
7741      * @return {Mixed} name The name field
7742      */
7743     getName: function(){
7744         return this.name;
7745     },
7746      /**
7747      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
7748      * @return {Mixed} value The field value
7749      */
7750     getValue : function(){
7751         
7752         var v = this.inputEl().getValue();
7753         
7754         return v;
7755     },
7756     /**
7757      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
7758      * @return {Mixed} value The field value
7759      */
7760     getRawValue : function(){
7761         var v = this.inputEl().getValue();
7762         
7763         return v;
7764     },
7765     
7766     /**
7767      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
7768      * @param {Mixed} value The value to set
7769      */
7770     setRawValue : function(v){
7771         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7772     },
7773     
7774     selectText : function(start, end){
7775         var v = this.getRawValue();
7776         if(v.length > 0){
7777             start = start === undefined ? 0 : start;
7778             end = end === undefined ? v.length : end;
7779             var d = this.inputEl().dom;
7780             if(d.setSelectionRange){
7781                 d.setSelectionRange(start, end);
7782             }else if(d.createTextRange){
7783                 var range = d.createTextRange();
7784                 range.moveStart("character", start);
7785                 range.moveEnd("character", v.length-end);
7786                 range.select();
7787             }
7788         }
7789     },
7790     
7791     /**
7792      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7793      * @param {Mixed} value The value to set
7794      */
7795     setValue : function(v){
7796         this.value = v;
7797         if(this.rendered){
7798             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7799             this.validate();
7800         }
7801     },
7802     
7803     /*
7804     processValue : function(value){
7805         if(this.stripCharsRe){
7806             var newValue = value.replace(this.stripCharsRe, '');
7807             if(newValue !== value){
7808                 this.setRawValue(newValue);
7809                 return newValue;
7810             }
7811         }
7812         return value;
7813     },
7814   */
7815     preFocus : function(){
7816         
7817         if(this.selectOnFocus){
7818             this.inputEl().dom.select();
7819         }
7820     },
7821     filterKeys : function(e){
7822         var k = e.getKey();
7823         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7824             return;
7825         }
7826         var c = e.getCharCode(), cc = String.fromCharCode(c);
7827         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7828             return;
7829         }
7830         if(!this.maskRe.test(cc)){
7831             e.stopEvent();
7832         }
7833     },
7834      /**
7835      * Clear any invalid styles/messages for this field
7836      */
7837     clearInvalid : function(){
7838         
7839         if(!this.el || this.preventMark){ // not rendered
7840             return;
7841         }
7842         this.el.removeClass(this.invalidClass);
7843         
7844         this.fireEvent('valid', this);
7845     },
7846     
7847      /**
7848      * Mark this field as valid
7849      */
7850     markValid : function(){
7851         if(!this.el  || this.preventMark){ // not rendered
7852             return;
7853         }
7854         
7855         this.el.removeClass([this.invalidClass, this.validClass]);
7856         
7857         if(this.disabled || this.allowBlank){
7858             return;
7859         }
7860         
7861         this.el.addClass(this.validClass);
7862         
7863         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7864             
7865             var feedback = this.el.select('.form-control-feedback', true).first();
7866             
7867             if(feedback){
7868                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7869                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7870             }
7871             
7872         }
7873         
7874         this.fireEvent('valid', this);
7875     },
7876     
7877      /**
7878      * Mark this field as invalid
7879      * @param {String} msg The validation message
7880      */
7881     markInvalid : function(msg){
7882         if(!this.el  || this.preventMark){ // not rendered
7883             return;
7884         }
7885         
7886         this.el.removeClass([this.invalidClass, this.validClass]);
7887         
7888         if(this.disabled || this.allowBlank){
7889             return;
7890         }
7891         
7892         this.el.addClass(this.invalidClass);
7893         
7894         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7895             
7896             var feedback = this.el.select('.form-control-feedback', true).first();
7897             
7898             if(feedback){
7899                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7900                 
7901                 if(this.getValue().length){
7902                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7903                 }
7904                 
7905             }
7906             
7907         }
7908         
7909         this.fireEvent('invalid', this, msg);
7910     },
7911     // private
7912     SafariOnKeyDown : function(event)
7913     {
7914         // this is a workaround for a password hang bug on chrome/ webkit.
7915         
7916         var isSelectAll = false;
7917         
7918         if(this.inputEl().dom.selectionEnd > 0){
7919             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7920         }
7921         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7922             event.preventDefault();
7923             this.setValue('');
7924             return;
7925         }
7926         
7927         if(isSelectAll  && event.getCharCode() > 31){ // not backspace and delete key
7928             
7929             event.preventDefault();
7930             // this is very hacky as keydown always get's upper case.
7931             //
7932             var cc = String.fromCharCode(event.getCharCode());
7933             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7934             
7935         }
7936     },
7937     adjustWidth : function(tag, w){
7938         tag = tag.toLowerCase();
7939         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7940             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7941                 if(tag == 'input'){
7942                     return w + 2;
7943                 }
7944                 if(tag == 'textarea'){
7945                     return w-2;
7946                 }
7947             }else if(Roo.isOpera){
7948                 if(tag == 'input'){
7949                     return w + 2;
7950                 }
7951                 if(tag == 'textarea'){
7952                     return w-2;
7953                 }
7954             }
7955         }
7956         return w;
7957     }
7958     
7959 });
7960
7961  
7962 /*
7963  * - LGPL
7964  *
7965  * Input
7966  * 
7967  */
7968
7969 /**
7970  * @class Roo.bootstrap.TextArea
7971  * @extends Roo.bootstrap.Input
7972  * Bootstrap TextArea class
7973  * @cfg {Number} cols Specifies the visible width of a text area
7974  * @cfg {Number} rows Specifies the visible number of lines in a text area
7975  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7976  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7977  * @cfg {string} html text
7978  * 
7979  * @constructor
7980  * Create a new TextArea
7981  * @param {Object} config The config object
7982  */
7983
7984 Roo.bootstrap.TextArea = function(config){
7985     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7986    
7987 };
7988
7989 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
7990      
7991     cols : false,
7992     rows : 5,
7993     readOnly : false,
7994     warp : 'soft',
7995     resize : false,
7996     value: false,
7997     html: false,
7998     
7999     getAutoCreate : function(){
8000         
8001         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8002         
8003         var id = Roo.id();
8004         
8005         var cfg = {};
8006         
8007         var input =  {
8008             tag: 'textarea',
8009             id : id,
8010             warp : this.warp,
8011             rows : this.rows,
8012             value : this.value || '',
8013             html: this.html || '',
8014             cls : 'form-control',
8015             placeholder : this.placeholder || '' 
8016             
8017         };
8018         
8019         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8020             input.maxLength = this.maxLength;
8021         }
8022         
8023         if(this.resize){
8024             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8025         }
8026         
8027         if(this.cols){
8028             input.cols = this.cols;
8029         }
8030         
8031         if (this.readOnly) {
8032             input.readonly = true;
8033         }
8034         
8035         if (this.name) {
8036             input.name = this.name;
8037         }
8038         
8039         if (this.size) {
8040             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8041         }
8042         
8043         var settings=this;
8044         ['xs','sm','md','lg'].map(function(size){
8045             if (settings[size]) {
8046                 cfg.cls += ' col-' + size + '-' + settings[size];
8047             }
8048         });
8049         
8050         var inputblock = input;
8051         
8052         if(this.hasFeedback && !this.allowBlank){
8053             
8054             var feedback = {
8055                 tag: 'span',
8056                 cls: 'glyphicon form-control-feedback'
8057             };
8058
8059             inputblock = {
8060                 cls : 'has-feedback',
8061                 cn :  [
8062                     input,
8063                     feedback
8064                 ] 
8065             };  
8066         }
8067         
8068         
8069         if (this.before || this.after) {
8070             
8071             inputblock = {
8072                 cls : 'input-group',
8073                 cn :  [] 
8074             };
8075             if (this.before) {
8076                 inputblock.cn.push({
8077                     tag :'span',
8078                     cls : 'input-group-addon',
8079                     html : this.before
8080                 });
8081             }
8082             
8083             inputblock.cn.push(input);
8084             
8085             if(this.hasFeedback && !this.allowBlank){
8086                 inputblock.cls += ' has-feedback';
8087                 inputblock.cn.push(feedback);
8088             }
8089             
8090             if (this.after) {
8091                 inputblock.cn.push({
8092                     tag :'span',
8093                     cls : 'input-group-addon',
8094                     html : this.after
8095                 });
8096             }
8097             
8098         }
8099         
8100         if (align ==='left' && this.fieldLabel.length) {
8101                 Roo.log("left and has label");
8102                 cfg.cn = [
8103                     
8104                     {
8105                         tag: 'label',
8106                         'for' :  id,
8107                         cls : 'control-label col-sm-' + this.labelWidth,
8108                         html : this.fieldLabel
8109                         
8110                     },
8111                     {
8112                         cls : "col-sm-" + (12 - this.labelWidth), 
8113                         cn: [
8114                             inputblock
8115                         ]
8116                     }
8117                     
8118                 ];
8119         } else if ( this.fieldLabel.length) {
8120                 Roo.log(" label");
8121                  cfg.cn = [
8122                    
8123                     {
8124                         tag: 'label',
8125                         //cls : 'input-group-addon',
8126                         html : this.fieldLabel
8127                         
8128                     },
8129                     
8130                     inputblock
8131                     
8132                 ];
8133
8134         } else {
8135             
8136                    Roo.log(" no label && no align");
8137                 cfg.cn = [
8138                     
8139                         inputblock
8140                     
8141                 ];
8142                 
8143                 
8144         }
8145         
8146         if (this.disabled) {
8147             input.disabled=true;
8148         }
8149         
8150         return cfg;
8151         
8152     },
8153     /**
8154      * return the real textarea element.
8155      */
8156     inputEl: function ()
8157     {
8158         return this.el.select('textarea.form-control',true).first();
8159     }
8160 });
8161
8162  
8163 /*
8164  * - LGPL
8165  *
8166  * trigger field - base class for combo..
8167  * 
8168  */
8169  
8170 /**
8171  * @class Roo.bootstrap.TriggerField
8172  * @extends Roo.bootstrap.Input
8173  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8174  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8175  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8176  * for which you can provide a custom implementation.  For example:
8177  * <pre><code>
8178 var trigger = new Roo.bootstrap.TriggerField();
8179 trigger.onTriggerClick = myTriggerFn;
8180 trigger.applyTo('my-field');
8181 </code></pre>
8182  *
8183  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8184  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8185  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
8186  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8187  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8188
8189  * @constructor
8190  * Create a new TriggerField.
8191  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8192  * to the base TextField)
8193  */
8194 Roo.bootstrap.TriggerField = function(config){
8195     this.mimicing = false;
8196     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8197 };
8198
8199 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
8200     /**
8201      * @cfg {String} triggerClass A CSS class to apply to the trigger
8202      */
8203      /**
8204      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8205      */
8206     hideTrigger:false,
8207
8208     /** @cfg {Boolean} grow @hide */
8209     /** @cfg {Number} growMin @hide */
8210     /** @cfg {Number} growMax @hide */
8211
8212     /**
8213      * @hide 
8214      * @method
8215      */
8216     autoSize: Roo.emptyFn,
8217     // private
8218     monitorTab : true,
8219     // private
8220     deferHeight : true,
8221
8222     
8223     actionMode : 'wrap',
8224     
8225     caret : false,
8226     
8227     
8228     getAutoCreate : function(){
8229        
8230         var align = this.labelAlign || this.parentLabelAlign();
8231         
8232         var id = Roo.id();
8233         
8234         var cfg = {
8235             cls: 'form-group' //input-group
8236         };
8237         
8238         
8239         var input =  {
8240             tag: 'input',
8241             id : id,
8242             type : this.inputType,
8243             cls : 'form-control',
8244             autocomplete: 'new-password',
8245             placeholder : this.placeholder || '' 
8246             
8247         };
8248         if (this.name) {
8249             input.name = this.name;
8250         }
8251         if (this.size) {
8252             input.cls += ' input-' + this.size;
8253         }
8254         
8255         if (this.disabled) {
8256             input.disabled=true;
8257         }
8258         
8259         var inputblock = input;
8260         
8261         if(this.hasFeedback && !this.allowBlank){
8262             
8263             var feedback = {
8264                 tag: 'span',
8265                 cls: 'glyphicon form-control-feedback'
8266             };
8267
8268             inputblock = {
8269                 cls : 'has-feedback',
8270                 cn :  [
8271                     input,
8272                     feedback
8273                 ] 
8274             };  
8275         }
8276         
8277         if (this.before || this.after) {
8278             
8279             inputblock = {
8280                 cls : 'input-group',
8281                 cn :  [] 
8282             };
8283             if (this.before) {
8284                 inputblock.cn.push({
8285                     tag :'span',
8286                     cls : 'input-group-addon',
8287                     html : this.before
8288                 });
8289             }
8290             
8291             inputblock.cn.push(input);
8292             
8293             if(this.hasFeedback && !this.allowBlank){
8294                 inputblock.cls += ' has-feedback';
8295                 inputblock.cn.push(feedback);
8296             }
8297             
8298             if (this.after) {
8299                 inputblock.cn.push({
8300                     tag :'span',
8301                     cls : 'input-group-addon',
8302                     html : this.after
8303                 });
8304             }
8305             
8306         };
8307         
8308         var box = {
8309             tag: 'div',
8310             cn: [
8311                 {
8312                     tag: 'input',
8313                     type : 'hidden',
8314                     cls: 'form-hidden-field'
8315                 },
8316                 inputblock
8317             ]
8318             
8319         };
8320         
8321         if(this.multiple){
8322             Roo.log('multiple');
8323             
8324             box = {
8325                 tag: 'div',
8326                 cn: [
8327                     {
8328                         tag: 'input',
8329                         type : 'hidden',
8330                         cls: 'form-hidden-field'
8331                     },
8332                     {
8333                         tag: 'ul',
8334                         cls: 'select2-choices',
8335                         cn:[
8336                             {
8337                                 tag: 'li',
8338                                 cls: 'select2-search-field',
8339                                 cn: [
8340
8341                                     inputblock
8342                                 ]
8343                             }
8344                         ]
8345                     }
8346                 ]
8347             }
8348         };
8349         
8350         var combobox = {
8351             cls: 'select2-container input-group',
8352             cn: [
8353                 box
8354 //                {
8355 //                    tag: 'ul',
8356 //                    cls: 'typeahead typeahead-long dropdown-menu',
8357 //                    style: 'display:none'
8358 //                }
8359             ]
8360         };
8361         
8362         if(!this.multiple && this.showToggleBtn){
8363             
8364             var caret = {
8365                         tag: 'span',
8366                         cls: 'caret'
8367              };
8368             if (this.caret != false) {
8369                 caret = {
8370                      tag: 'i',
8371                      cls: 'fa fa-' + this.caret
8372                 };
8373                 
8374             }
8375             
8376             combobox.cn.push({
8377                 tag :'span',
8378                 cls : 'input-group-addon btn dropdown-toggle',
8379                 cn : [
8380                     caret,
8381                     {
8382                         tag: 'span',
8383                         cls: 'combobox-clear',
8384                         cn  : [
8385                             {
8386                                 tag : 'i',
8387                                 cls: 'icon-remove'
8388                             }
8389                         ]
8390                     }
8391                 ]
8392
8393             })
8394         }
8395         
8396         if(this.multiple){
8397             combobox.cls += ' select2-container-multi';
8398         }
8399         
8400         if (align ==='left' && this.fieldLabel.length) {
8401             
8402                 Roo.log("left and has label");
8403                 cfg.cn = [
8404                     
8405                     {
8406                         tag: 'label',
8407                         'for' :  id,
8408                         cls : 'control-label col-sm-' + this.labelWidth,
8409                         html : this.fieldLabel
8410                         
8411                     },
8412                     {
8413                         cls : "col-sm-" + (12 - this.labelWidth), 
8414                         cn: [
8415                             combobox
8416                         ]
8417                     }
8418                     
8419                 ];
8420         } else if ( this.fieldLabel.length) {
8421                 Roo.log(" label");
8422                  cfg.cn = [
8423                    
8424                     {
8425                         tag: 'label',
8426                         //cls : 'input-group-addon',
8427                         html : this.fieldLabel
8428                         
8429                     },
8430                     
8431                     combobox
8432                     
8433                 ];
8434
8435         } else {
8436             
8437                 Roo.log(" no label && no align");
8438                 cfg = combobox
8439                      
8440                 
8441         }
8442          
8443         var settings=this;
8444         ['xs','sm','md','lg'].map(function(size){
8445             if (settings[size]) {
8446                 cfg.cls += ' col-' + size + '-' + settings[size];
8447             }
8448         });
8449         
8450         return cfg;
8451         
8452     },
8453     
8454     
8455     
8456     // private
8457     onResize : function(w, h){
8458 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8459 //        if(typeof w == 'number'){
8460 //            var x = w - this.trigger.getWidth();
8461 //            this.inputEl().setWidth(this.adjustWidth('input', x));
8462 //            this.trigger.setStyle('left', x+'px');
8463 //        }
8464     },
8465
8466     // private
8467     adjustSize : Roo.BoxComponent.prototype.adjustSize,
8468
8469     // private
8470     getResizeEl : function(){
8471         return this.inputEl();
8472     },
8473
8474     // private
8475     getPositionEl : function(){
8476         return this.inputEl();
8477     },
8478
8479     // private
8480     alignErrorIcon : function(){
8481         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8482     },
8483
8484     // private
8485     initEvents : function(){
8486         
8487         this.createList();
8488         
8489         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8490         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8491         if(!this.multiple && this.showToggleBtn){
8492             this.trigger = this.el.select('span.dropdown-toggle',true).first();
8493             if(this.hideTrigger){
8494                 this.trigger.setDisplayed(false);
8495             }
8496             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8497         }
8498         
8499         if(this.multiple){
8500             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8501         }
8502         
8503         //this.trigger.addClassOnOver('x-form-trigger-over');
8504         //this.trigger.addClassOnClick('x-form-trigger-click');
8505         
8506         //if(!this.width){
8507         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8508         //}
8509     },
8510     
8511     createList : function()
8512     {
8513         this.list = Roo.get(document.body).createChild({
8514             tag: 'ul',
8515             cls: 'typeahead typeahead-long dropdown-menu',
8516             style: 'display:none'
8517         });
8518         
8519         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8520         
8521     },
8522
8523     // private
8524     initTrigger : function(){
8525        
8526     },
8527
8528     // private
8529     onDestroy : function(){
8530         if(this.trigger){
8531             this.trigger.removeAllListeners();
8532           //  this.trigger.remove();
8533         }
8534         //if(this.wrap){
8535         //    this.wrap.remove();
8536         //}
8537         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8538     },
8539
8540     // private
8541     onFocus : function(){
8542         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8543         /*
8544         if(!this.mimicing){
8545             this.wrap.addClass('x-trigger-wrap-focus');
8546             this.mimicing = true;
8547             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8548             if(this.monitorTab){
8549                 this.el.on("keydown", this.checkTab, this);
8550             }
8551         }
8552         */
8553     },
8554
8555     // private
8556     checkTab : function(e){
8557         if(e.getKey() == e.TAB){
8558             this.triggerBlur();
8559         }
8560     },
8561
8562     // private
8563     onBlur : function(){
8564         // do nothing
8565     },
8566
8567     // private
8568     mimicBlur : function(e, t){
8569         /*
8570         if(!this.wrap.contains(t) && this.validateBlur()){
8571             this.triggerBlur();
8572         }
8573         */
8574     },
8575
8576     // private
8577     triggerBlur : function(){
8578         this.mimicing = false;
8579         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8580         if(this.monitorTab){
8581             this.el.un("keydown", this.checkTab, this);
8582         }
8583         //this.wrap.removeClass('x-trigger-wrap-focus');
8584         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8585     },
8586
8587     // private
8588     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8589     validateBlur : function(e, t){
8590         return true;
8591     },
8592
8593     // private
8594     onDisable : function(){
8595         this.inputEl().dom.disabled = true;
8596         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8597         //if(this.wrap){
8598         //    this.wrap.addClass('x-item-disabled');
8599         //}
8600     },
8601
8602     // private
8603     onEnable : function(){
8604         this.inputEl().dom.disabled = false;
8605         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8606         //if(this.wrap){
8607         //    this.el.removeClass('x-item-disabled');
8608         //}
8609     },
8610
8611     // private
8612     onShow : function(){
8613         var ae = this.getActionEl();
8614         
8615         if(ae){
8616             ae.dom.style.display = '';
8617             ae.dom.style.visibility = 'visible';
8618         }
8619     },
8620
8621     // private
8622     
8623     onHide : function(){
8624         var ae = this.getActionEl();
8625         ae.dom.style.display = 'none';
8626     },
8627
8628     /**
8629      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
8630      * by an implementing function.
8631      * @method
8632      * @param {EventObject} e
8633      */
8634     onTriggerClick : Roo.emptyFn
8635 });
8636  /*
8637  * Based on:
8638  * Ext JS Library 1.1.1
8639  * Copyright(c) 2006-2007, Ext JS, LLC.
8640  *
8641  * Originally Released Under LGPL - original licence link has changed is not relivant.
8642  *
8643  * Fork - LGPL
8644  * <script type="text/javascript">
8645  */
8646
8647
8648 /**
8649  * @class Roo.data.SortTypes
8650  * @singleton
8651  * Defines the default sorting (casting?) comparison functions used when sorting data.
8652  */
8653 Roo.data.SortTypes = {
8654     /**
8655      * Default sort that does nothing
8656      * @param {Mixed} s The value being converted
8657      * @return {Mixed} The comparison value
8658      */
8659     none : function(s){
8660         return s;
8661     },
8662     
8663     /**
8664      * The regular expression used to strip tags
8665      * @type {RegExp}
8666      * @property
8667      */
8668     stripTagsRE : /<\/?[^>]+>/gi,
8669     
8670     /**
8671      * Strips all HTML tags to sort on text only
8672      * @param {Mixed} s The value being converted
8673      * @return {String} The comparison value
8674      */
8675     asText : function(s){
8676         return String(s).replace(this.stripTagsRE, "");
8677     },
8678     
8679     /**
8680      * Strips all HTML tags to sort on text only - Case insensitive
8681      * @param {Mixed} s The value being converted
8682      * @return {String} The comparison value
8683      */
8684     asUCText : function(s){
8685         return String(s).toUpperCase().replace(this.stripTagsRE, "");
8686     },
8687     
8688     /**
8689      * Case insensitive string
8690      * @param {Mixed} s The value being converted
8691      * @return {String} The comparison value
8692      */
8693     asUCString : function(s) {
8694         return String(s).toUpperCase();
8695     },
8696     
8697     /**
8698      * Date sorting
8699      * @param {Mixed} s The value being converted
8700      * @return {Number} The comparison value
8701      */
8702     asDate : function(s) {
8703         if(!s){
8704             return 0;
8705         }
8706         if(s instanceof Date){
8707             return s.getTime();
8708         }
8709         return Date.parse(String(s));
8710     },
8711     
8712     /**
8713      * Float sorting
8714      * @param {Mixed} s The value being converted
8715      * @return {Float} The comparison value
8716      */
8717     asFloat : function(s) {
8718         var val = parseFloat(String(s).replace(/,/g, ""));
8719         if(isNaN(val)) val = 0;
8720         return val;
8721     },
8722     
8723     /**
8724      * Integer sorting
8725      * @param {Mixed} s The value being converted
8726      * @return {Number} The comparison value
8727      */
8728     asInt : function(s) {
8729         var val = parseInt(String(s).replace(/,/g, ""));
8730         if(isNaN(val)) val = 0;
8731         return val;
8732     }
8733 };/*
8734  * Based on:
8735  * Ext JS Library 1.1.1
8736  * Copyright(c) 2006-2007, Ext JS, LLC.
8737  *
8738  * Originally Released Under LGPL - original licence link has changed is not relivant.
8739  *
8740  * Fork - LGPL
8741  * <script type="text/javascript">
8742  */
8743
8744 /**
8745 * @class Roo.data.Record
8746  * Instances of this class encapsulate both record <em>definition</em> information, and record
8747  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8748  * to access Records cached in an {@link Roo.data.Store} object.<br>
8749  * <p>
8750  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8751  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8752  * objects.<br>
8753  * <p>
8754  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8755  * @constructor
8756  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8757  * {@link #create}. The parameters are the same.
8758  * @param {Array} data An associative Array of data values keyed by the field name.
8759  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8760  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8761  * not specified an integer id is generated.
8762  */
8763 Roo.data.Record = function(data, id){
8764     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8765     this.data = data;
8766 };
8767
8768 /**
8769  * Generate a constructor for a specific record layout.
8770  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8771  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8772  * Each field definition object may contain the following properties: <ul>
8773  * <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,
8774  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8775  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8776  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8777  * is being used, then this is a string containing the javascript expression to reference the data relative to 
8778  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8779  * to the data item relative to the record element. If the mapping expression is the same as the field name,
8780  * this may be omitted.</p></li>
8781  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8782  * <ul><li>auto (Default, implies no conversion)</li>
8783  * <li>string</li>
8784  * <li>int</li>
8785  * <li>float</li>
8786  * <li>boolean</li>
8787  * <li>date</li></ul></p></li>
8788  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8789  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8790  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8791  * by the Reader into an object that will be stored in the Record. It is passed the
8792  * following parameters:<ul>
8793  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8794  * </ul></p></li>
8795  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8796  * </ul>
8797  * <br>usage:<br><pre><code>
8798 var TopicRecord = Roo.data.Record.create(
8799     {name: 'title', mapping: 'topic_title'},
8800     {name: 'author', mapping: 'username'},
8801     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8802     {name: 'lastPost', mapping: 'post_time', type: 'date'},
8803     {name: 'lastPoster', mapping: 'user2'},
8804     {name: 'excerpt', mapping: 'post_text'}
8805 );
8806
8807 var myNewRecord = new TopicRecord({
8808     title: 'Do my job please',
8809     author: 'noobie',
8810     totalPosts: 1,
8811     lastPost: new Date(),
8812     lastPoster: 'Animal',
8813     excerpt: 'No way dude!'
8814 });
8815 myStore.add(myNewRecord);
8816 </code></pre>
8817  * @method create
8818  * @static
8819  */
8820 Roo.data.Record.create = function(o){
8821     var f = function(){
8822         f.superclass.constructor.apply(this, arguments);
8823     };
8824     Roo.extend(f, Roo.data.Record);
8825     var p = f.prototype;
8826     p.fields = new Roo.util.MixedCollection(false, function(field){
8827         return field.name;
8828     });
8829     for(var i = 0, len = o.length; i < len; i++){
8830         p.fields.add(new Roo.data.Field(o[i]));
8831     }
8832     f.getField = function(name){
8833         return p.fields.get(name);  
8834     };
8835     return f;
8836 };
8837
8838 Roo.data.Record.AUTO_ID = 1000;
8839 Roo.data.Record.EDIT = 'edit';
8840 Roo.data.Record.REJECT = 'reject';
8841 Roo.data.Record.COMMIT = 'commit';
8842
8843 Roo.data.Record.prototype = {
8844     /**
8845      * Readonly flag - true if this record has been modified.
8846      * @type Boolean
8847      */
8848     dirty : false,
8849     editing : false,
8850     error: null,
8851     modified: null,
8852
8853     // private
8854     join : function(store){
8855         this.store = store;
8856     },
8857
8858     /**
8859      * Set the named field to the specified value.
8860      * @param {String} name The name of the field to set.
8861      * @param {Object} value The value to set the field to.
8862      */
8863     set : function(name, value){
8864         if(this.data[name] == value){
8865             return;
8866         }
8867         this.dirty = true;
8868         if(!this.modified){
8869             this.modified = {};
8870         }
8871         if(typeof this.modified[name] == 'undefined'){
8872             this.modified[name] = this.data[name];
8873         }
8874         this.data[name] = value;
8875         if(!this.editing && this.store){
8876             this.store.afterEdit(this);
8877         }       
8878     },
8879
8880     /**
8881      * Get the value of the named field.
8882      * @param {String} name The name of the field to get the value of.
8883      * @return {Object} The value of the field.
8884      */
8885     get : function(name){
8886         return this.data[name]; 
8887     },
8888
8889     // private
8890     beginEdit : function(){
8891         this.editing = true;
8892         this.modified = {}; 
8893     },
8894
8895     // private
8896     cancelEdit : function(){
8897         this.editing = false;
8898         delete this.modified;
8899     },
8900
8901     // private
8902     endEdit : function(){
8903         this.editing = false;
8904         if(this.dirty && this.store){
8905             this.store.afterEdit(this);
8906         }
8907     },
8908
8909     /**
8910      * Usually called by the {@link Roo.data.Store} which owns the Record.
8911      * Rejects all changes made to the Record since either creation, or the last commit operation.
8912      * Modified fields are reverted to their original values.
8913      * <p>
8914      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8915      * of reject operations.
8916      */
8917     reject : function(){
8918         var m = this.modified;
8919         for(var n in m){
8920             if(typeof m[n] != "function"){
8921                 this.data[n] = m[n];
8922             }
8923         }
8924         this.dirty = false;
8925         delete this.modified;
8926         this.editing = false;
8927         if(this.store){
8928             this.store.afterReject(this);
8929         }
8930     },
8931
8932     /**
8933      * Usually called by the {@link Roo.data.Store} which owns the Record.
8934      * Commits all changes made to the Record since either creation, or the last commit operation.
8935      * <p>
8936      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8937      * of commit operations.
8938      */
8939     commit : function(){
8940         this.dirty = false;
8941         delete this.modified;
8942         this.editing = false;
8943         if(this.store){
8944             this.store.afterCommit(this);
8945         }
8946     },
8947
8948     // private
8949     hasError : function(){
8950         return this.error != null;
8951     },
8952
8953     // private
8954     clearError : function(){
8955         this.error = null;
8956     },
8957
8958     /**
8959      * Creates a copy of this record.
8960      * @param {String} id (optional) A new record id if you don't want to use this record's id
8961      * @return {Record}
8962      */
8963     copy : function(newId) {
8964         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8965     }
8966 };/*
8967  * Based on:
8968  * Ext JS Library 1.1.1
8969  * Copyright(c) 2006-2007, Ext JS, LLC.
8970  *
8971  * Originally Released Under LGPL - original licence link has changed is not relivant.
8972  *
8973  * Fork - LGPL
8974  * <script type="text/javascript">
8975  */
8976
8977
8978
8979 /**
8980  * @class Roo.data.Store
8981  * @extends Roo.util.Observable
8982  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8983  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8984  * <p>
8985  * 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
8986  * has no knowledge of the format of the data returned by the Proxy.<br>
8987  * <p>
8988  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8989  * instances from the data object. These records are cached and made available through accessor functions.
8990  * @constructor
8991  * Creates a new Store.
8992  * @param {Object} config A config object containing the objects needed for the Store to access data,
8993  * and read the data into Records.
8994  */
8995 Roo.data.Store = function(config){
8996     this.data = new Roo.util.MixedCollection(false);
8997     this.data.getKey = function(o){
8998         return o.id;
8999     };
9000     this.baseParams = {};
9001     // private
9002     this.paramNames = {
9003         "start" : "start",
9004         "limit" : "limit",
9005         "sort" : "sort",
9006         "dir" : "dir",
9007         "multisort" : "_multisort"
9008     };
9009
9010     if(config && config.data){
9011         this.inlineData = config.data;
9012         delete config.data;
9013     }
9014
9015     Roo.apply(this, config);
9016     
9017     if(this.reader){ // reader passed
9018         this.reader = Roo.factory(this.reader, Roo.data);
9019         this.reader.xmodule = this.xmodule || false;
9020         if(!this.recordType){
9021             this.recordType = this.reader.recordType;
9022         }
9023         if(this.reader.onMetaChange){
9024             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9025         }
9026     }
9027
9028     if(this.recordType){
9029         this.fields = this.recordType.prototype.fields;
9030     }
9031     this.modified = [];
9032
9033     this.addEvents({
9034         /**
9035          * @event datachanged
9036          * Fires when the data cache has changed, and a widget which is using this Store
9037          * as a Record cache should refresh its view.
9038          * @param {Store} this
9039          */
9040         datachanged : true,
9041         /**
9042          * @event metachange
9043          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9044          * @param {Store} this
9045          * @param {Object} meta The JSON metadata
9046          */
9047         metachange : true,
9048         /**
9049          * @event add
9050          * Fires when Records have been added to the Store
9051          * @param {Store} this
9052          * @param {Roo.data.Record[]} records The array of Records added
9053          * @param {Number} index The index at which the record(s) were added
9054          */
9055         add : true,
9056         /**
9057          * @event remove
9058          * Fires when a Record has been removed from the Store
9059          * @param {Store} this
9060          * @param {Roo.data.Record} record The Record that was removed
9061          * @param {Number} index The index at which the record was removed
9062          */
9063         remove : true,
9064         /**
9065          * @event update
9066          * Fires when a Record has been updated
9067          * @param {Store} this
9068          * @param {Roo.data.Record} record The Record that was updated
9069          * @param {String} operation The update operation being performed.  Value may be one of:
9070          * <pre><code>
9071  Roo.data.Record.EDIT
9072  Roo.data.Record.REJECT
9073  Roo.data.Record.COMMIT
9074          * </code></pre>
9075          */
9076         update : true,
9077         /**
9078          * @event clear
9079          * Fires when the data cache has been cleared.
9080          * @param {Store} this
9081          */
9082         clear : true,
9083         /**
9084          * @event beforeload
9085          * Fires before a request is made for a new data object.  If the beforeload handler returns false
9086          * the load action will be canceled.
9087          * @param {Store} this
9088          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9089          */
9090         beforeload : true,
9091         /**
9092          * @event beforeloadadd
9093          * Fires after a new set of Records has been loaded.
9094          * @param {Store} this
9095          * @param {Roo.data.Record[]} records The Records that were loaded
9096          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9097          */
9098         beforeloadadd : true,
9099         /**
9100          * @event load
9101          * Fires after a new set of Records has been loaded, before they are added to the store.
9102          * @param {Store} this
9103          * @param {Roo.data.Record[]} records The Records that were loaded
9104          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9105          * @params {Object} return from reader
9106          */
9107         load : true,
9108         /**
9109          * @event loadexception
9110          * Fires if an exception occurs in the Proxy during loading.
9111          * Called with the signature of the Proxy's "loadexception" event.
9112          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9113          * 
9114          * @param {Proxy} 
9115          * @param {Object} return from JsonData.reader() - success, totalRecords, records
9116          * @param {Object} load options 
9117          * @param {Object} jsonData from your request (normally this contains the Exception)
9118          */
9119         loadexception : true
9120     });
9121     
9122     if(this.proxy){
9123         this.proxy = Roo.factory(this.proxy, Roo.data);
9124         this.proxy.xmodule = this.xmodule || false;
9125         this.relayEvents(this.proxy,  ["loadexception"]);
9126     }
9127     this.sortToggle = {};
9128     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9129
9130     Roo.data.Store.superclass.constructor.call(this);
9131
9132     if(this.inlineData){
9133         this.loadData(this.inlineData);
9134         delete this.inlineData;
9135     }
9136 };
9137
9138 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9139      /**
9140     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
9141     * without a remote query - used by combo/forms at present.
9142     */
9143     
9144     /**
9145     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9146     */
9147     /**
9148     * @cfg {Array} data Inline data to be loaded when the store is initialized.
9149     */
9150     /**
9151     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9152     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9153     */
9154     /**
9155     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9156     * on any HTTP request
9157     */
9158     /**
9159     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9160     */
9161     /**
9162     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9163     */
9164     multiSort: false,
9165     /**
9166     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9167     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9168     */
9169     remoteSort : false,
9170
9171     /**
9172     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9173      * loaded or when a record is removed. (defaults to false).
9174     */
9175     pruneModifiedRecords : false,
9176
9177     // private
9178     lastOptions : null,
9179
9180     /**
9181      * Add Records to the Store and fires the add event.
9182      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9183      */
9184     add : function(records){
9185         records = [].concat(records);
9186         for(var i = 0, len = records.length; i < len; i++){
9187             records[i].join(this);
9188         }
9189         var index = this.data.length;
9190         this.data.addAll(records);
9191         this.fireEvent("add", this, records, index);
9192     },
9193
9194     /**
9195      * Remove a Record from the Store and fires the remove event.
9196      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9197      */
9198     remove : function(record){
9199         var index = this.data.indexOf(record);
9200         this.data.removeAt(index);
9201         if(this.pruneModifiedRecords){
9202             this.modified.remove(record);
9203         }
9204         this.fireEvent("remove", this, record, index);
9205     },
9206
9207     /**
9208      * Remove all Records from the Store and fires the clear event.
9209      */
9210     removeAll : function(){
9211         this.data.clear();
9212         if(this.pruneModifiedRecords){
9213             this.modified = [];
9214         }
9215         this.fireEvent("clear", this);
9216     },
9217
9218     /**
9219      * Inserts Records to the Store at the given index and fires the add event.
9220      * @param {Number} index The start index at which to insert the passed Records.
9221      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9222      */
9223     insert : function(index, records){
9224         records = [].concat(records);
9225         for(var i = 0, len = records.length; i < len; i++){
9226             this.data.insert(index, records[i]);
9227             records[i].join(this);
9228         }
9229         this.fireEvent("add", this, records, index);
9230     },
9231
9232     /**
9233      * Get the index within the cache of the passed Record.
9234      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9235      * @return {Number} The index of the passed Record. Returns -1 if not found.
9236      */
9237     indexOf : function(record){
9238         return this.data.indexOf(record);
9239     },
9240
9241     /**
9242      * Get the index within the cache of the Record with the passed id.
9243      * @param {String} id The id of the Record to find.
9244      * @return {Number} The index of the Record. Returns -1 if not found.
9245      */
9246     indexOfId : function(id){
9247         return this.data.indexOfKey(id);
9248     },
9249
9250     /**
9251      * Get the Record with the specified id.
9252      * @param {String} id The id of the Record to find.
9253      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9254      */
9255     getById : function(id){
9256         return this.data.key(id);
9257     },
9258
9259     /**
9260      * Get the Record at the specified index.
9261      * @param {Number} index The index of the Record to find.
9262      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9263      */
9264     getAt : function(index){
9265         return this.data.itemAt(index);
9266     },
9267
9268     /**
9269      * Returns a range of Records between specified indices.
9270      * @param {Number} startIndex (optional) The starting index (defaults to 0)
9271      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9272      * @return {Roo.data.Record[]} An array of Records
9273      */
9274     getRange : function(start, end){
9275         return this.data.getRange(start, end);
9276     },
9277
9278     // private
9279     storeOptions : function(o){
9280         o = Roo.apply({}, o);
9281         delete o.callback;
9282         delete o.scope;
9283         this.lastOptions = o;
9284     },
9285
9286     /**
9287      * Loads the Record cache from the configured Proxy using the configured Reader.
9288      * <p>
9289      * If using remote paging, then the first load call must specify the <em>start</em>
9290      * and <em>limit</em> properties in the options.params property to establish the initial
9291      * position within the dataset, and the number of Records to cache on each read from the Proxy.
9292      * <p>
9293      * <strong>It is important to note that for remote data sources, loading is asynchronous,
9294      * and this call will return before the new data has been loaded. Perform any post-processing
9295      * in a callback function, or in a "load" event handler.</strong>
9296      * <p>
9297      * @param {Object} options An object containing properties which control loading options:<ul>
9298      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9299      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9300      * passed the following arguments:<ul>
9301      * <li>r : Roo.data.Record[]</li>
9302      * <li>options: Options object from the load call</li>
9303      * <li>success: Boolean success indicator</li></ul></li>
9304      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9305      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9306      * </ul>
9307      */
9308     load : function(options){
9309         options = options || {};
9310         if(this.fireEvent("beforeload", this, options) !== false){
9311             this.storeOptions(options);
9312             var p = Roo.apply(options.params || {}, this.baseParams);
9313             // if meta was not loaded from remote source.. try requesting it.
9314             if (!this.reader.metaFromRemote) {
9315                 p._requestMeta = 1;
9316             }
9317             if(this.sortInfo && this.remoteSort){
9318                 var pn = this.paramNames;
9319                 p[pn["sort"]] = this.sortInfo.field;
9320                 p[pn["dir"]] = this.sortInfo.direction;
9321             }
9322             if (this.multiSort) {
9323                 var pn = this.paramNames;
9324                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9325             }
9326             
9327             this.proxy.load(p, this.reader, this.loadRecords, this, options);
9328         }
9329     },
9330
9331     /**
9332      * Reloads the Record cache from the configured Proxy using the configured Reader and
9333      * the options from the last load operation performed.
9334      * @param {Object} options (optional) An object containing properties which may override the options
9335      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9336      * the most recently used options are reused).
9337      */
9338     reload : function(options){
9339         this.load(Roo.applyIf(options||{}, this.lastOptions));
9340     },
9341
9342     // private
9343     // Called as a callback by the Reader during a load operation.
9344     loadRecords : function(o, options, success){
9345         if(!o || success === false){
9346             if(success !== false){
9347                 this.fireEvent("load", this, [], options, o);
9348             }
9349             if(options.callback){
9350                 options.callback.call(options.scope || this, [], options, false);
9351             }
9352             return;
9353         }
9354         // if data returned failure - throw an exception.
9355         if (o.success === false) {
9356             // show a message if no listener is registered.
9357             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9358                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9359             }
9360             // loadmask wil be hooked into this..
9361             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9362             return;
9363         }
9364         var r = o.records, t = o.totalRecords || r.length;
9365         
9366         this.fireEvent("beforeloadadd", this, r, options, o);
9367         
9368         if(!options || options.add !== true){
9369             if(this.pruneModifiedRecords){
9370                 this.modified = [];
9371             }
9372             for(var i = 0, len = r.length; i < len; i++){
9373                 r[i].join(this);
9374             }
9375             if(this.snapshot){
9376                 this.data = this.snapshot;
9377                 delete this.snapshot;
9378             }
9379             this.data.clear();
9380             this.data.addAll(r);
9381             this.totalLength = t;
9382             this.applySort();
9383             this.fireEvent("datachanged", this);
9384         }else{
9385             this.totalLength = Math.max(t, this.data.length+r.length);
9386             this.add(r);
9387         }
9388         this.fireEvent("load", this, r, options, o);
9389         if(options.callback){
9390             options.callback.call(options.scope || this, r, options, true);
9391         }
9392     },
9393
9394
9395     /**
9396      * Loads data from a passed data block. A Reader which understands the format of the data
9397      * must have been configured in the constructor.
9398      * @param {Object} data The data block from which to read the Records.  The format of the data expected
9399      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9400      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9401      */
9402     loadData : function(o, append){
9403         var r = this.reader.readRecords(o);
9404         this.loadRecords(r, {add: append}, true);
9405     },
9406
9407     /**
9408      * Gets the number of cached records.
9409      * <p>
9410      * <em>If using paging, this may not be the total size of the dataset. If the data object
9411      * used by the Reader contains the dataset size, then the getTotalCount() function returns
9412      * the data set size</em>
9413      */
9414     getCount : function(){
9415         return this.data.length || 0;
9416     },
9417
9418     /**
9419      * Gets the total number of records in the dataset as returned by the server.
9420      * <p>
9421      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9422      * the dataset size</em>
9423      */
9424     getTotalCount : function(){
9425         return this.totalLength || 0;
9426     },
9427
9428     /**
9429      * Returns the sort state of the Store as an object with two properties:
9430      * <pre><code>
9431  field {String} The name of the field by which the Records are sorted
9432  direction {String} The sort order, "ASC" or "DESC"
9433      * </code></pre>
9434      */
9435     getSortState : function(){
9436         return this.sortInfo;
9437     },
9438
9439     // private
9440     applySort : function(){
9441         if(this.sortInfo && !this.remoteSort){
9442             var s = this.sortInfo, f = s.field;
9443             var st = this.fields.get(f).sortType;
9444             var fn = function(r1, r2){
9445                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9446                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9447             };
9448             this.data.sort(s.direction, fn);
9449             if(this.snapshot && this.snapshot != this.data){
9450                 this.snapshot.sort(s.direction, fn);
9451             }
9452         }
9453     },
9454
9455     /**
9456      * Sets the default sort column and order to be used by the next load operation.
9457      * @param {String} fieldName The name of the field to sort by.
9458      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9459      */
9460     setDefaultSort : function(field, dir){
9461         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9462     },
9463
9464     /**
9465      * Sort the Records.
9466      * If remote sorting is used, the sort is performed on the server, and the cache is
9467      * reloaded. If local sorting is used, the cache is sorted internally.
9468      * @param {String} fieldName The name of the field to sort by.
9469      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9470      */
9471     sort : function(fieldName, dir){
9472         var f = this.fields.get(fieldName);
9473         if(!dir){
9474             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9475             
9476             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9477                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9478             }else{
9479                 dir = f.sortDir;
9480             }
9481         }
9482         this.sortToggle[f.name] = dir;
9483         this.sortInfo = {field: f.name, direction: dir};
9484         if(!this.remoteSort){
9485             this.applySort();
9486             this.fireEvent("datachanged", this);
9487         }else{
9488             this.load(this.lastOptions);
9489         }
9490     },
9491
9492     /**
9493      * Calls the specified function for each of the Records in the cache.
9494      * @param {Function} fn The function to call. The Record is passed as the first parameter.
9495      * Returning <em>false</em> aborts and exits the iteration.
9496      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9497      */
9498     each : function(fn, scope){
9499         this.data.each(fn, scope);
9500     },
9501
9502     /**
9503      * Gets all records modified since the last commit.  Modified records are persisted across load operations
9504      * (e.g., during paging).
9505      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9506      */
9507     getModifiedRecords : function(){
9508         return this.modified;
9509     },
9510
9511     // private
9512     createFilterFn : function(property, value, anyMatch){
9513         if(!value.exec){ // not a regex
9514             value = String(value);
9515             if(value.length == 0){
9516                 return false;
9517             }
9518             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9519         }
9520         return function(r){
9521             return value.test(r.data[property]);
9522         };
9523     },
9524
9525     /**
9526      * Sums the value of <i>property</i> for each record between start and end and returns the result.
9527      * @param {String} property A field on your records
9528      * @param {Number} start The record index to start at (defaults to 0)
9529      * @param {Number} end The last record index to include (defaults to length - 1)
9530      * @return {Number} The sum
9531      */
9532     sum : function(property, start, end){
9533         var rs = this.data.items, v = 0;
9534         start = start || 0;
9535         end = (end || end === 0) ? end : rs.length-1;
9536
9537         for(var i = start; i <= end; i++){
9538             v += (rs[i].data[property] || 0);
9539         }
9540         return v;
9541     },
9542
9543     /**
9544      * Filter the records by a specified property.
9545      * @param {String} field A field on your records
9546      * @param {String/RegExp} value Either a string that the field
9547      * should start with or a RegExp to test against the field
9548      * @param {Boolean} anyMatch True to match any part not just the beginning
9549      */
9550     filter : function(property, value, anyMatch){
9551         var fn = this.createFilterFn(property, value, anyMatch);
9552         return fn ? this.filterBy(fn) : this.clearFilter();
9553     },
9554
9555     /**
9556      * Filter by a function. The specified function will be called with each
9557      * record in this data source. If the function returns true the record is included,
9558      * otherwise it is filtered.
9559      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9560      * @param {Object} scope (optional) The scope of the function (defaults to this)
9561      */
9562     filterBy : function(fn, scope){
9563         this.snapshot = this.snapshot || this.data;
9564         this.data = this.queryBy(fn, scope||this);
9565         this.fireEvent("datachanged", this);
9566     },
9567
9568     /**
9569      * Query the records by a specified property.
9570      * @param {String} field A field on your records
9571      * @param {String/RegExp} value Either a string that the field
9572      * should start with or a RegExp to test against the field
9573      * @param {Boolean} anyMatch True to match any part not just the beginning
9574      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9575      */
9576     query : function(property, value, anyMatch){
9577         var fn = this.createFilterFn(property, value, anyMatch);
9578         return fn ? this.queryBy(fn) : this.data.clone();
9579     },
9580
9581     /**
9582      * Query by a function. The specified function will be called with each
9583      * record in this data source. If the function returns true the record is included
9584      * in the results.
9585      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9586      * @param {Object} scope (optional) The scope of the function (defaults to this)
9587       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9588      **/
9589     queryBy : function(fn, scope){
9590         var data = this.snapshot || this.data;
9591         return data.filterBy(fn, scope||this);
9592     },
9593
9594     /**
9595      * Collects unique values for a particular dataIndex from this store.
9596      * @param {String} dataIndex The property to collect
9597      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9598      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9599      * @return {Array} An array of the unique values
9600      **/
9601     collect : function(dataIndex, allowNull, bypassFilter){
9602         var d = (bypassFilter === true && this.snapshot) ?
9603                 this.snapshot.items : this.data.items;
9604         var v, sv, r = [], l = {};
9605         for(var i = 0, len = d.length; i < len; i++){
9606             v = d[i].data[dataIndex];
9607             sv = String(v);
9608             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9609                 l[sv] = true;
9610                 r[r.length] = v;
9611             }
9612         }
9613         return r;
9614     },
9615
9616     /**
9617      * Revert to a view of the Record cache with no filtering applied.
9618      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9619      */
9620     clearFilter : function(suppressEvent){
9621         if(this.snapshot && this.snapshot != this.data){
9622             this.data = this.snapshot;
9623             delete this.snapshot;
9624             if(suppressEvent !== true){
9625                 this.fireEvent("datachanged", this);
9626             }
9627         }
9628     },
9629
9630     // private
9631     afterEdit : function(record){
9632         if(this.modified.indexOf(record) == -1){
9633             this.modified.push(record);
9634         }
9635         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9636     },
9637     
9638     // private
9639     afterReject : function(record){
9640         this.modified.remove(record);
9641         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9642     },
9643
9644     // private
9645     afterCommit : function(record){
9646         this.modified.remove(record);
9647         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9648     },
9649
9650     /**
9651      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9652      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9653      */
9654     commitChanges : function(){
9655         var m = this.modified.slice(0);
9656         this.modified = [];
9657         for(var i = 0, len = m.length; i < len; i++){
9658             m[i].commit();
9659         }
9660     },
9661
9662     /**
9663      * Cancel outstanding changes on all changed records.
9664      */
9665     rejectChanges : function(){
9666         var m = this.modified.slice(0);
9667         this.modified = [];
9668         for(var i = 0, len = m.length; i < len; i++){
9669             m[i].reject();
9670         }
9671     },
9672
9673     onMetaChange : function(meta, rtype, o){
9674         this.recordType = rtype;
9675         this.fields = rtype.prototype.fields;
9676         delete this.snapshot;
9677         this.sortInfo = meta.sortInfo || this.sortInfo;
9678         this.modified = [];
9679         this.fireEvent('metachange', this, this.reader.meta);
9680     },
9681     
9682     moveIndex : function(data, type)
9683     {
9684         var index = this.indexOf(data);
9685         
9686         var newIndex = index + type;
9687         
9688         this.remove(data);
9689         
9690         this.insert(newIndex, data);
9691         
9692     }
9693 });/*
9694  * Based on:
9695  * Ext JS Library 1.1.1
9696  * Copyright(c) 2006-2007, Ext JS, LLC.
9697  *
9698  * Originally Released Under LGPL - original licence link has changed is not relivant.
9699  *
9700  * Fork - LGPL
9701  * <script type="text/javascript">
9702  */
9703
9704 /**
9705  * @class Roo.data.SimpleStore
9706  * @extends Roo.data.Store
9707  * Small helper class to make creating Stores from Array data easier.
9708  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9709  * @cfg {Array} fields An array of field definition objects, or field name strings.
9710  * @cfg {Array} data The multi-dimensional array of data
9711  * @constructor
9712  * @param {Object} config
9713  */
9714 Roo.data.SimpleStore = function(config){
9715     Roo.data.SimpleStore.superclass.constructor.call(this, {
9716         isLocal : true,
9717         reader: new Roo.data.ArrayReader({
9718                 id: config.id
9719             },
9720             Roo.data.Record.create(config.fields)
9721         ),
9722         proxy : new Roo.data.MemoryProxy(config.data)
9723     });
9724     this.load();
9725 };
9726 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9727  * Based on:
9728  * Ext JS Library 1.1.1
9729  * Copyright(c) 2006-2007, Ext JS, LLC.
9730  *
9731  * Originally Released Under LGPL - original licence link has changed is not relivant.
9732  *
9733  * Fork - LGPL
9734  * <script type="text/javascript">
9735  */
9736
9737 /**
9738 /**
9739  * @extends Roo.data.Store
9740  * @class Roo.data.JsonStore
9741  * Small helper class to make creating Stores for JSON data easier. <br/>
9742 <pre><code>
9743 var store = new Roo.data.JsonStore({
9744     url: 'get-images.php',
9745     root: 'images',
9746     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9747 });
9748 </code></pre>
9749  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9750  * JsonReader and HttpProxy (unless inline data is provided).</b>
9751  * @cfg {Array} fields An array of field definition objects, or field name strings.
9752  * @constructor
9753  * @param {Object} config
9754  */
9755 Roo.data.JsonStore = function(c){
9756     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9757         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9758         reader: new Roo.data.JsonReader(c, c.fields)
9759     }));
9760 };
9761 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9762  * Based on:
9763  * Ext JS Library 1.1.1
9764  * Copyright(c) 2006-2007, Ext JS, LLC.
9765  *
9766  * Originally Released Under LGPL - original licence link has changed is not relivant.
9767  *
9768  * Fork - LGPL
9769  * <script type="text/javascript">
9770  */
9771
9772  
9773 Roo.data.Field = function(config){
9774     if(typeof config == "string"){
9775         config = {name: config};
9776     }
9777     Roo.apply(this, config);
9778     
9779     if(!this.type){
9780         this.type = "auto";
9781     }
9782     
9783     var st = Roo.data.SortTypes;
9784     // named sortTypes are supported, here we look them up
9785     if(typeof this.sortType == "string"){
9786         this.sortType = st[this.sortType];
9787     }
9788     
9789     // set default sortType for strings and dates
9790     if(!this.sortType){
9791         switch(this.type){
9792             case "string":
9793                 this.sortType = st.asUCString;
9794                 break;
9795             case "date":
9796                 this.sortType = st.asDate;
9797                 break;
9798             default:
9799                 this.sortType = st.none;
9800         }
9801     }
9802
9803     // define once
9804     var stripRe = /[\$,%]/g;
9805
9806     // prebuilt conversion function for this field, instead of
9807     // switching every time we're reading a value
9808     if(!this.convert){
9809         var cv, dateFormat = this.dateFormat;
9810         switch(this.type){
9811             case "":
9812             case "auto":
9813             case undefined:
9814                 cv = function(v){ return v; };
9815                 break;
9816             case "string":
9817                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9818                 break;
9819             case "int":
9820                 cv = function(v){
9821                     return v !== undefined && v !== null && v !== '' ?
9822                            parseInt(String(v).replace(stripRe, ""), 10) : '';
9823                     };
9824                 break;
9825             case "float":
9826                 cv = function(v){
9827                     return v !== undefined && v !== null && v !== '' ?
9828                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
9829                     };
9830                 break;
9831             case "bool":
9832             case "boolean":
9833                 cv = function(v){ return v === true || v === "true" || v == 1; };
9834                 break;
9835             case "date":
9836                 cv = function(v){
9837                     if(!v){
9838                         return '';
9839                     }
9840                     if(v instanceof Date){
9841                         return v;
9842                     }
9843                     if(dateFormat){
9844                         if(dateFormat == "timestamp"){
9845                             return new Date(v*1000);
9846                         }
9847                         return Date.parseDate(v, dateFormat);
9848                     }
9849                     var parsed = Date.parse(v);
9850                     return parsed ? new Date(parsed) : null;
9851                 };
9852              break;
9853             
9854         }
9855         this.convert = cv;
9856     }
9857 };
9858
9859 Roo.data.Field.prototype = {
9860     dateFormat: null,
9861     defaultValue: "",
9862     mapping: null,
9863     sortType : null,
9864     sortDir : "ASC"
9865 };/*
9866  * Based on:
9867  * Ext JS Library 1.1.1
9868  * Copyright(c) 2006-2007, Ext JS, LLC.
9869  *
9870  * Originally Released Under LGPL - original licence link has changed is not relivant.
9871  *
9872  * Fork - LGPL
9873  * <script type="text/javascript">
9874  */
9875  
9876 // Base class for reading structured data from a data source.  This class is intended to be
9877 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9878
9879 /**
9880  * @class Roo.data.DataReader
9881  * Base class for reading structured data from a data source.  This class is intended to be
9882  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9883  */
9884
9885 Roo.data.DataReader = function(meta, recordType){
9886     
9887     this.meta = meta;
9888     
9889     this.recordType = recordType instanceof Array ? 
9890         Roo.data.Record.create(recordType) : recordType;
9891 };
9892
9893 Roo.data.DataReader.prototype = {
9894      /**
9895      * Create an empty record
9896      * @param {Object} data (optional) - overlay some values
9897      * @return {Roo.data.Record} record created.
9898      */
9899     newRow :  function(d) {
9900         var da =  {};
9901         this.recordType.prototype.fields.each(function(c) {
9902             switch( c.type) {
9903                 case 'int' : da[c.name] = 0; break;
9904                 case 'date' : da[c.name] = new Date(); break;
9905                 case 'float' : da[c.name] = 0.0; break;
9906                 case 'boolean' : da[c.name] = false; break;
9907                 default : da[c.name] = ""; break;
9908             }
9909             
9910         });
9911         return new this.recordType(Roo.apply(da, d));
9912     }
9913     
9914 };/*
9915  * Based on:
9916  * Ext JS Library 1.1.1
9917  * Copyright(c) 2006-2007, Ext JS, LLC.
9918  *
9919  * Originally Released Under LGPL - original licence link has changed is not relivant.
9920  *
9921  * Fork - LGPL
9922  * <script type="text/javascript">
9923  */
9924
9925 /**
9926  * @class Roo.data.DataProxy
9927  * @extends Roo.data.Observable
9928  * This class is an abstract base class for implementations which provide retrieval of
9929  * unformatted data objects.<br>
9930  * <p>
9931  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9932  * (of the appropriate type which knows how to parse the data object) to provide a block of
9933  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9934  * <p>
9935  * Custom implementations must implement the load method as described in
9936  * {@link Roo.data.HttpProxy#load}.
9937  */
9938 Roo.data.DataProxy = function(){
9939     this.addEvents({
9940         /**
9941          * @event beforeload
9942          * Fires before a network request is made to retrieve a data object.
9943          * @param {Object} This DataProxy object.
9944          * @param {Object} params The params parameter to the load function.
9945          */
9946         beforeload : true,
9947         /**
9948          * @event load
9949          * Fires before the load method's callback is called.
9950          * @param {Object} This DataProxy object.
9951          * @param {Object} o The data object.
9952          * @param {Object} arg The callback argument object passed to the load function.
9953          */
9954         load : true,
9955         /**
9956          * @event loadexception
9957          * Fires if an Exception occurs during data retrieval.
9958          * @param {Object} This DataProxy object.
9959          * @param {Object} o The data object.
9960          * @param {Object} arg The callback argument object passed to the load function.
9961          * @param {Object} e The Exception.
9962          */
9963         loadexception : true
9964     });
9965     Roo.data.DataProxy.superclass.constructor.call(this);
9966 };
9967
9968 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9969
9970     /**
9971      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9972      */
9973 /*
9974  * Based on:
9975  * Ext JS Library 1.1.1
9976  * Copyright(c) 2006-2007, Ext JS, LLC.
9977  *
9978  * Originally Released Under LGPL - original licence link has changed is not relivant.
9979  *
9980  * Fork - LGPL
9981  * <script type="text/javascript">
9982  */
9983 /**
9984  * @class Roo.data.MemoryProxy
9985  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9986  * to the Reader when its load method is called.
9987  * @constructor
9988  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9989  */
9990 Roo.data.MemoryProxy = function(data){
9991     if (data.data) {
9992         data = data.data;
9993     }
9994     Roo.data.MemoryProxy.superclass.constructor.call(this);
9995     this.data = data;
9996 };
9997
9998 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9999     /**
10000      * Load data from the requested source (in this case an in-memory
10001      * data object passed to the constructor), read the data object into
10002      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10003      * process that block using the passed callback.
10004      * @param {Object} params This parameter is not used by the MemoryProxy class.
10005      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10006      * object into a block of Roo.data.Records.
10007      * @param {Function} callback The function into which to pass the block of Roo.data.records.
10008      * The function must be passed <ul>
10009      * <li>The Record block object</li>
10010      * <li>The "arg" argument from the load function</li>
10011      * <li>A boolean success indicator</li>
10012      * </ul>
10013      * @param {Object} scope The scope in which to call the callback
10014      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10015      */
10016     load : function(params, reader, callback, scope, arg){
10017         params = params || {};
10018         var result;
10019         try {
10020             result = reader.readRecords(this.data);
10021         }catch(e){
10022             this.fireEvent("loadexception", this, arg, null, e);
10023             callback.call(scope, null, arg, false);
10024             return;
10025         }
10026         callback.call(scope, result, arg, true);
10027     },
10028     
10029     // private
10030     update : function(params, records){
10031         
10032     }
10033 });/*
10034  * Based on:
10035  * Ext JS Library 1.1.1
10036  * Copyright(c) 2006-2007, Ext JS, LLC.
10037  *
10038  * Originally Released Under LGPL - original licence link has changed is not relivant.
10039  *
10040  * Fork - LGPL
10041  * <script type="text/javascript">
10042  */
10043 /**
10044  * @class Roo.data.HttpProxy
10045  * @extends Roo.data.DataProxy
10046  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10047  * configured to reference a certain URL.<br><br>
10048  * <p>
10049  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10050  * from which the running page was served.<br><br>
10051  * <p>
10052  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10053  * <p>
10054  * Be aware that to enable the browser to parse an XML document, the server must set
10055  * the Content-Type header in the HTTP response to "text/xml".
10056  * @constructor
10057  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10058  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
10059  * will be used to make the request.
10060  */
10061 Roo.data.HttpProxy = function(conn){
10062     Roo.data.HttpProxy.superclass.constructor.call(this);
10063     // is conn a conn config or a real conn?
10064     this.conn = conn;
10065     this.useAjax = !conn || !conn.events;
10066   
10067 };
10068
10069 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10070     // thse are take from connection...
10071     
10072     /**
10073      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10074      */
10075     /**
10076      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10077      * extra parameters to each request made by this object. (defaults to undefined)
10078      */
10079     /**
10080      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10081      *  to each request made by this object. (defaults to undefined)
10082      */
10083     /**
10084      * @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)
10085      */
10086     /**
10087      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10088      */
10089      /**
10090      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10091      * @type Boolean
10092      */
10093   
10094
10095     /**
10096      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10097      * @type Boolean
10098      */
10099     /**
10100      * Return the {@link Roo.data.Connection} object being used by this Proxy.
10101      * @return {Connection} The Connection object. This object may be used to subscribe to events on
10102      * a finer-grained basis than the DataProxy events.
10103      */
10104     getConnection : function(){
10105         return this.useAjax ? Roo.Ajax : this.conn;
10106     },
10107
10108     /**
10109      * Load data from the configured {@link Roo.data.Connection}, read the data object into
10110      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10111      * process that block using the passed callback.
10112      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10113      * for the request to the remote server.
10114      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10115      * object into a block of Roo.data.Records.
10116      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10117      * The function must be passed <ul>
10118      * <li>The Record block object</li>
10119      * <li>The "arg" argument from the load function</li>
10120      * <li>A boolean success indicator</li>
10121      * </ul>
10122      * @param {Object} scope The scope in which to call the callback
10123      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10124      */
10125     load : function(params, reader, callback, scope, arg){
10126         if(this.fireEvent("beforeload", this, params) !== false){
10127             var  o = {
10128                 params : params || {},
10129                 request: {
10130                     callback : callback,
10131                     scope : scope,
10132                     arg : arg
10133                 },
10134                 reader: reader,
10135                 callback : this.loadResponse,
10136                 scope: this
10137             };
10138             if(this.useAjax){
10139                 Roo.applyIf(o, this.conn);
10140                 if(this.activeRequest){
10141                     Roo.Ajax.abort(this.activeRequest);
10142                 }
10143                 this.activeRequest = Roo.Ajax.request(o);
10144             }else{
10145                 this.conn.request(o);
10146             }
10147         }else{
10148             callback.call(scope||this, null, arg, false);
10149         }
10150     },
10151
10152     // private
10153     loadResponse : function(o, success, response){
10154         delete this.activeRequest;
10155         if(!success){
10156             this.fireEvent("loadexception", this, o, response);
10157             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10158             return;
10159         }
10160         var result;
10161         try {
10162             result = o.reader.read(response);
10163         }catch(e){
10164             this.fireEvent("loadexception", this, o, response, e);
10165             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10166             return;
10167         }
10168         
10169         this.fireEvent("load", this, o, o.request.arg);
10170         o.request.callback.call(o.request.scope, result, o.request.arg, true);
10171     },
10172
10173     // private
10174     update : function(dataSet){
10175
10176     },
10177
10178     // private
10179     updateResponse : function(dataSet){
10180
10181     }
10182 });/*
10183  * Based on:
10184  * Ext JS Library 1.1.1
10185  * Copyright(c) 2006-2007, Ext JS, LLC.
10186  *
10187  * Originally Released Under LGPL - original licence link has changed is not relivant.
10188  *
10189  * Fork - LGPL
10190  * <script type="text/javascript">
10191  */
10192
10193 /**
10194  * @class Roo.data.ScriptTagProxy
10195  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10196  * other than the originating domain of the running page.<br><br>
10197  * <p>
10198  * <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
10199  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10200  * <p>
10201  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10202  * source code that is used as the source inside a &lt;script> tag.<br><br>
10203  * <p>
10204  * In order for the browser to process the returned data, the server must wrap the data object
10205  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10206  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10207  * depending on whether the callback name was passed:
10208  * <p>
10209  * <pre><code>
10210 boolean scriptTag = false;
10211 String cb = request.getParameter("callback");
10212 if (cb != null) {
10213     scriptTag = true;
10214     response.setContentType("text/javascript");
10215 } else {
10216     response.setContentType("application/x-json");
10217 }
10218 Writer out = response.getWriter();
10219 if (scriptTag) {
10220     out.write(cb + "(");
10221 }
10222 out.print(dataBlock.toJsonString());
10223 if (scriptTag) {
10224     out.write(");");
10225 }
10226 </pre></code>
10227  *
10228  * @constructor
10229  * @param {Object} config A configuration object.
10230  */
10231 Roo.data.ScriptTagProxy = function(config){
10232     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10233     Roo.apply(this, config);
10234     this.head = document.getElementsByTagName("head")[0];
10235 };
10236
10237 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10238
10239 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10240     /**
10241      * @cfg {String} url The URL from which to request the data object.
10242      */
10243     /**
10244      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10245      */
10246     timeout : 30000,
10247     /**
10248      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10249      * the server the name of the callback function set up by the load call to process the returned data object.
10250      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10251      * javascript output which calls this named function passing the data object as its only parameter.
10252      */
10253     callbackParam : "callback",
10254     /**
10255      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10256      * name to the request.
10257      */
10258     nocache : true,
10259
10260     /**
10261      * Load data from the configured URL, read the data object into
10262      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10263      * process that block using the passed callback.
10264      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10265      * for the request to the remote server.
10266      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10267      * object into a block of Roo.data.Records.
10268      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10269      * The function must be passed <ul>
10270      * <li>The Record block object</li>
10271      * <li>The "arg" argument from the load function</li>
10272      * <li>A boolean success indicator</li>
10273      * </ul>
10274      * @param {Object} scope The scope in which to call the callback
10275      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10276      */
10277     load : function(params, reader, callback, scope, arg){
10278         if(this.fireEvent("beforeload", this, params) !== false){
10279
10280             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10281
10282             var url = this.url;
10283             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10284             if(this.nocache){
10285                 url += "&_dc=" + (new Date().getTime());
10286             }
10287             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10288             var trans = {
10289                 id : transId,
10290                 cb : "stcCallback"+transId,
10291                 scriptId : "stcScript"+transId,
10292                 params : params,
10293                 arg : arg,
10294                 url : url,
10295                 callback : callback,
10296                 scope : scope,
10297                 reader : reader
10298             };
10299             var conn = this;
10300
10301             window[trans.cb] = function(o){
10302                 conn.handleResponse(o, trans);
10303             };
10304
10305             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10306
10307             if(this.autoAbort !== false){
10308                 this.abort();
10309             }
10310
10311             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10312
10313             var script = document.createElement("script");
10314             script.setAttribute("src", url);
10315             script.setAttribute("type", "text/javascript");
10316             script.setAttribute("id", trans.scriptId);
10317             this.head.appendChild(script);
10318
10319             this.trans = trans;
10320         }else{
10321             callback.call(scope||this, null, arg, false);
10322         }
10323     },
10324
10325     // private
10326     isLoading : function(){
10327         return this.trans ? true : false;
10328     },
10329
10330     /**
10331      * Abort the current server request.
10332      */
10333     abort : function(){
10334         if(this.isLoading()){
10335             this.destroyTrans(this.trans);
10336         }
10337     },
10338
10339     // private
10340     destroyTrans : function(trans, isLoaded){
10341         this.head.removeChild(document.getElementById(trans.scriptId));
10342         clearTimeout(trans.timeoutId);
10343         if(isLoaded){
10344             window[trans.cb] = undefined;
10345             try{
10346                 delete window[trans.cb];
10347             }catch(e){}
10348         }else{
10349             // if hasn't been loaded, wait for load to remove it to prevent script error
10350             window[trans.cb] = function(){
10351                 window[trans.cb] = undefined;
10352                 try{
10353                     delete window[trans.cb];
10354                 }catch(e){}
10355             };
10356         }
10357     },
10358
10359     // private
10360     handleResponse : function(o, trans){
10361         this.trans = false;
10362         this.destroyTrans(trans, true);
10363         var result;
10364         try {
10365             result = trans.reader.readRecords(o);
10366         }catch(e){
10367             this.fireEvent("loadexception", this, o, trans.arg, e);
10368             trans.callback.call(trans.scope||window, null, trans.arg, false);
10369             return;
10370         }
10371         this.fireEvent("load", this, o, trans.arg);
10372         trans.callback.call(trans.scope||window, result, trans.arg, true);
10373     },
10374
10375     // private
10376     handleFailure : function(trans){
10377         this.trans = false;
10378         this.destroyTrans(trans, false);
10379         this.fireEvent("loadexception", this, null, trans.arg);
10380         trans.callback.call(trans.scope||window, null, trans.arg, false);
10381     }
10382 });/*
10383  * Based on:
10384  * Ext JS Library 1.1.1
10385  * Copyright(c) 2006-2007, Ext JS, LLC.
10386  *
10387  * Originally Released Under LGPL - original licence link has changed is not relivant.
10388  *
10389  * Fork - LGPL
10390  * <script type="text/javascript">
10391  */
10392
10393 /**
10394  * @class Roo.data.JsonReader
10395  * @extends Roo.data.DataReader
10396  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10397  * based on mappings in a provided Roo.data.Record constructor.
10398  * 
10399  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10400  * in the reply previously. 
10401  * 
10402  * <p>
10403  * Example code:
10404  * <pre><code>
10405 var RecordDef = Roo.data.Record.create([
10406     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
10407     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
10408 ]);
10409 var myReader = new Roo.data.JsonReader({
10410     totalProperty: "results",    // The property which contains the total dataset size (optional)
10411     root: "rows",                // The property which contains an Array of row objects
10412     id: "id"                     // The property within each row object that provides an ID for the record (optional)
10413 }, RecordDef);
10414 </code></pre>
10415  * <p>
10416  * This would consume a JSON file like this:
10417  * <pre><code>
10418 { 'results': 2, 'rows': [
10419     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10420     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10421 }
10422 </code></pre>
10423  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10424  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10425  * paged from the remote server.
10426  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10427  * @cfg {String} root name of the property which contains the Array of row objects.
10428  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10429  * @constructor
10430  * Create a new JsonReader
10431  * @param {Object} meta Metadata configuration options
10432  * @param {Object} recordType Either an Array of field definition objects,
10433  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10434  */
10435 Roo.data.JsonReader = function(meta, recordType){
10436     
10437     meta = meta || {};
10438     // set some defaults:
10439     Roo.applyIf(meta, {
10440         totalProperty: 'total',
10441         successProperty : 'success',
10442         root : 'data',
10443         id : 'id'
10444     });
10445     
10446     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10447 };
10448 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10449     
10450     /**
10451      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
10452      * Used by Store query builder to append _requestMeta to params.
10453      * 
10454      */
10455     metaFromRemote : false,
10456     /**
10457      * This method is only used by a DataProxy which has retrieved data from a remote server.
10458      * @param {Object} response The XHR object which contains the JSON data in its responseText.
10459      * @return {Object} data A data block which is used by an Roo.data.Store object as
10460      * a cache of Roo.data.Records.
10461      */
10462     read : function(response){
10463         var json = response.responseText;
10464        
10465         var o = /* eval:var:o */ eval("("+json+")");
10466         if(!o) {
10467             throw {message: "JsonReader.read: Json object not found"};
10468         }
10469         
10470         if(o.metaData){
10471             
10472             delete this.ef;
10473             this.metaFromRemote = true;
10474             this.meta = o.metaData;
10475             this.recordType = Roo.data.Record.create(o.metaData.fields);
10476             this.onMetaChange(this.meta, this.recordType, o);
10477         }
10478         return this.readRecords(o);
10479     },
10480
10481     // private function a store will implement
10482     onMetaChange : function(meta, recordType, o){
10483
10484     },
10485
10486     /**
10487          * @ignore
10488          */
10489     simpleAccess: function(obj, subsc) {
10490         return obj[subsc];
10491     },
10492
10493         /**
10494          * @ignore
10495          */
10496     getJsonAccessor: function(){
10497         var re = /[\[\.]/;
10498         return function(expr) {
10499             try {
10500                 return(re.test(expr))
10501                     ? new Function("obj", "return obj." + expr)
10502                     : function(obj){
10503                         return obj[expr];
10504                     };
10505             } catch(e){}
10506             return Roo.emptyFn;
10507         };
10508     }(),
10509
10510     /**
10511      * Create a data block containing Roo.data.Records from an XML document.
10512      * @param {Object} o An object which contains an Array of row objects in the property specified
10513      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10514      * which contains the total size of the dataset.
10515      * @return {Object} data A data block which is used by an Roo.data.Store object as
10516      * a cache of Roo.data.Records.
10517      */
10518     readRecords : function(o){
10519         /**
10520          * After any data loads, the raw JSON data is available for further custom processing.
10521          * @type Object
10522          */
10523         this.o = o;
10524         var s = this.meta, Record = this.recordType,
10525             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10526
10527 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
10528         if (!this.ef) {
10529             if(s.totalProperty) {
10530                     this.getTotal = this.getJsonAccessor(s.totalProperty);
10531                 }
10532                 if(s.successProperty) {
10533                     this.getSuccess = this.getJsonAccessor(s.successProperty);
10534                 }
10535                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10536                 if (s.id) {
10537                         var g = this.getJsonAccessor(s.id);
10538                         this.getId = function(rec) {
10539                                 var r = g(rec);  
10540                                 return (r === undefined || r === "") ? null : r;
10541                         };
10542                 } else {
10543                         this.getId = function(){return null;};
10544                 }
10545             this.ef = [];
10546             for(var jj = 0; jj < fl; jj++){
10547                 f = fi[jj];
10548                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10549                 this.ef[jj] = this.getJsonAccessor(map);
10550             }
10551         }
10552
10553         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10554         if(s.totalProperty){
10555             var vt = parseInt(this.getTotal(o), 10);
10556             if(!isNaN(vt)){
10557                 totalRecords = vt;
10558             }
10559         }
10560         if(s.successProperty){
10561             var vs = this.getSuccess(o);
10562             if(vs === false || vs === 'false'){
10563                 success = false;
10564             }
10565         }
10566         var records = [];
10567         for(var i = 0; i < c; i++){
10568                 var n = root[i];
10569             var values = {};
10570             var id = this.getId(n);
10571             for(var j = 0; j < fl; j++){
10572                 f = fi[j];
10573             var v = this.ef[j](n);
10574             if (!f.convert) {
10575                 Roo.log('missing convert for ' + f.name);
10576                 Roo.log(f);
10577                 continue;
10578             }
10579             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10580             }
10581             var record = new Record(values, id);
10582             record.json = n;
10583             records[i] = record;
10584         }
10585         return {
10586             raw : o,
10587             success : success,
10588             records : records,
10589             totalRecords : totalRecords
10590         };
10591     }
10592 });/*
10593  * Based on:
10594  * Ext JS Library 1.1.1
10595  * Copyright(c) 2006-2007, Ext JS, LLC.
10596  *
10597  * Originally Released Under LGPL - original licence link has changed is not relivant.
10598  *
10599  * Fork - LGPL
10600  * <script type="text/javascript">
10601  */
10602
10603 /**
10604  * @class Roo.data.ArrayReader
10605  * @extends Roo.data.DataReader
10606  * Data reader class to create an Array of Roo.data.Record objects from an Array.
10607  * Each element of that Array represents a row of data fields. The
10608  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10609  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10610  * <p>
10611  * Example code:.
10612  * <pre><code>
10613 var RecordDef = Roo.data.Record.create([
10614     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
10615     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
10616 ]);
10617 var myReader = new Roo.data.ArrayReader({
10618     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
10619 }, RecordDef);
10620 </code></pre>
10621  * <p>
10622  * This would consume an Array like this:
10623  * <pre><code>
10624 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10625   </code></pre>
10626  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10627  * @constructor
10628  * Create a new JsonReader
10629  * @param {Object} meta Metadata configuration options.
10630  * @param {Object} recordType Either an Array of field definition objects
10631  * as specified to {@link Roo.data.Record#create},
10632  * or an {@link Roo.data.Record} object
10633  * created using {@link Roo.data.Record#create}.
10634  */
10635 Roo.data.ArrayReader = function(meta, recordType){
10636     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10637 };
10638
10639 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10640     /**
10641      * Create a data block containing Roo.data.Records from an XML document.
10642      * @param {Object} o An Array of row objects which represents the dataset.
10643      * @return {Object} data A data block which is used by an Roo.data.Store object as
10644      * a cache of Roo.data.Records.
10645      */
10646     readRecords : function(o){
10647         var sid = this.meta ? this.meta.id : null;
10648         var recordType = this.recordType, fields = recordType.prototype.fields;
10649         var records = [];
10650         var root = o;
10651             for(var i = 0; i < root.length; i++){
10652                     var n = root[i];
10653                 var values = {};
10654                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10655                 for(var j = 0, jlen = fields.length; j < jlen; j++){
10656                 var f = fields.items[j];
10657                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10658                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10659                 v = f.convert(v);
10660                 values[f.name] = v;
10661             }
10662                 var record = new recordType(values, id);
10663                 record.json = n;
10664                 records[records.length] = record;
10665             }
10666             return {
10667                 records : records,
10668                 totalRecords : records.length
10669             };
10670     }
10671 });/*
10672  * - LGPL
10673  * * 
10674  */
10675
10676 /**
10677  * @class Roo.bootstrap.ComboBox
10678  * @extends Roo.bootstrap.TriggerField
10679  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10680  * @cfg {Boolean} append (true|false) default false
10681  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10682  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10683  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10684  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10685  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10686  * @constructor
10687  * Create a new ComboBox.
10688  * @param {Object} config Configuration options
10689  */
10690 Roo.bootstrap.ComboBox = function(config){
10691     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10692     this.addEvents({
10693         /**
10694          * @event expand
10695          * Fires when the dropdown list is expanded
10696              * @param {Roo.bootstrap.ComboBox} combo This combo box
10697              */
10698         'expand' : true,
10699         /**
10700          * @event collapse
10701          * Fires when the dropdown list is collapsed
10702              * @param {Roo.bootstrap.ComboBox} combo This combo box
10703              */
10704         'collapse' : true,
10705         /**
10706          * @event beforeselect
10707          * Fires before a list item is selected. Return false to cancel the selection.
10708              * @param {Roo.bootstrap.ComboBox} combo This combo box
10709              * @param {Roo.data.Record} record The data record returned from the underlying store
10710              * @param {Number} index The index of the selected item in the dropdown list
10711              */
10712         'beforeselect' : true,
10713         /**
10714          * @event select
10715          * Fires when a list item is selected
10716              * @param {Roo.bootstrap.ComboBox} combo This combo box
10717              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10718              * @param {Number} index The index of the selected item in the dropdown list
10719              */
10720         'select' : true,
10721         /**
10722          * @event beforequery
10723          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10724          * The event object passed has these properties:
10725              * @param {Roo.bootstrap.ComboBox} combo This combo box
10726              * @param {String} query The query
10727              * @param {Boolean} forceAll true to force "all" query
10728              * @param {Boolean} cancel true to cancel the query
10729              * @param {Object} e The query event object
10730              */
10731         'beforequery': true,
10732          /**
10733          * @event add
10734          * Fires when the 'add' icon is pressed (add a listener to enable add button)
10735              * @param {Roo.bootstrap.ComboBox} combo This combo box
10736              */
10737         'add' : true,
10738         /**
10739          * @event edit
10740          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10741              * @param {Roo.bootstrap.ComboBox} combo This combo box
10742              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10743              */
10744         'edit' : true,
10745         /**
10746          * @event remove
10747          * Fires when the remove value from the combobox array
10748              * @param {Roo.bootstrap.ComboBox} combo This combo box
10749              */
10750         'remove' : true
10751         
10752     });
10753     
10754     this.item = [];
10755     this.tickItems = [];
10756     
10757     this.selectedIndex = -1;
10758     if(this.mode == 'local'){
10759         if(config.queryDelay === undefined){
10760             this.queryDelay = 10;
10761         }
10762         if(config.minChars === undefined){
10763             this.minChars = 0;
10764         }
10765     }
10766 };
10767
10768 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10769      
10770     /**
10771      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10772      * rendering into an Roo.Editor, defaults to false)
10773      */
10774     /**
10775      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10776      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10777      */
10778     /**
10779      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10780      */
10781     /**
10782      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10783      * the dropdown list (defaults to undefined, with no header element)
10784      */
10785
10786      /**
10787      * @cfg {String/Roo.Template} tpl The template to use to render the output
10788      */
10789      
10790      /**
10791      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10792      */
10793     listWidth: undefined,
10794     /**
10795      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10796      * mode = 'remote' or 'text' if mode = 'local')
10797      */
10798     displayField: undefined,
10799     /**
10800      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10801      * mode = 'remote' or 'value' if mode = 'local'). 
10802      * Note: use of a valueField requires the user make a selection
10803      * in order for a value to be mapped.
10804      */
10805     valueField: undefined,
10806     
10807     
10808     /**
10809      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10810      * field's data value (defaults to the underlying DOM element's name)
10811      */
10812     hiddenName: undefined,
10813     /**
10814      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10815      */
10816     listClass: '',
10817     /**
10818      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10819      */
10820     selectedClass: 'active',
10821     
10822     /**
10823      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10824      */
10825     shadow:'sides',
10826     /**
10827      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10828      * anchor positions (defaults to 'tl-bl')
10829      */
10830     listAlign: 'tl-bl?',
10831     /**
10832      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10833      */
10834     maxHeight: 300,
10835     /**
10836      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
10837      * query specified by the allQuery config option (defaults to 'query')
10838      */
10839     triggerAction: 'query',
10840     /**
10841      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10842      * (defaults to 4, does not apply if editable = false)
10843      */
10844     minChars : 4,
10845     /**
10846      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10847      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10848      */
10849     typeAhead: false,
10850     /**
10851      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10852      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10853      */
10854     queryDelay: 500,
10855     /**
10856      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10857      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10858      */
10859     pageSize: 0,
10860     /**
10861      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10862      * when editable = true (defaults to false)
10863      */
10864     selectOnFocus:false,
10865     /**
10866      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10867      */
10868     queryParam: 'query',
10869     /**
10870      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10871      * when mode = 'remote' (defaults to 'Loading...')
10872      */
10873     loadingText: 'Loading...',
10874     /**
10875      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10876      */
10877     resizable: false,
10878     /**
10879      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10880      */
10881     handleHeight : 8,
10882     /**
10883      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10884      * traditional select (defaults to true)
10885      */
10886     editable: true,
10887     /**
10888      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10889      */
10890     allQuery: '',
10891     /**
10892      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10893      */
10894     mode: 'remote',
10895     /**
10896      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10897      * listWidth has a higher value)
10898      */
10899     minListWidth : 70,
10900     /**
10901      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10902      * allow the user to set arbitrary text into the field (defaults to false)
10903      */
10904     forceSelection:false,
10905     /**
10906      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10907      * if typeAhead = true (defaults to 250)
10908      */
10909     typeAheadDelay : 250,
10910     /**
10911      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10912      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10913      */
10914     valueNotFoundText : undefined,
10915     /**
10916      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10917      */
10918     blockFocus : false,
10919     
10920     /**
10921      * @cfg {Boolean} disableClear Disable showing of clear button.
10922      */
10923     disableClear : false,
10924     /**
10925      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10926      */
10927     alwaysQuery : false,
10928     
10929     /**
10930      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10931      */
10932     multiple : false,
10933     
10934     /**
10935      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10936      */
10937     invalidClass : "has-warning",
10938     
10939     /**
10940      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10941      */
10942     validClass : "has-success",
10943     
10944     //private
10945     addicon : false,
10946     editicon: false,
10947     
10948     page: 0,
10949     hasQuery: false,
10950     append: false,
10951     loadNext: false,
10952     autoFocus : true,
10953     tickable : false,
10954     btnPosition : 'right',
10955     triggerList : true,
10956     showToggleBtn : true,
10957     // element that contains real text value.. (when hidden is used..)
10958     
10959     getAutoCreate : function()
10960     {
10961         var cfg = false;
10962         
10963         /*
10964          *  Normal ComboBox
10965          */
10966         if(!this.tickable){
10967             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10968             return cfg;
10969         }
10970         
10971         /*
10972          *  ComboBox with tickable selections
10973          */
10974              
10975         var align = this.labelAlign || this.parentLabelAlign();
10976         
10977         cfg = {
10978             cls : 'form-group roo-combobox-tickable' //input-group
10979         };
10980         
10981         var buttons = {
10982             tag : 'div',
10983             cls : 'tickable-buttons',
10984             cn : [
10985                 {
10986                     tag : 'button',
10987                     type : 'button',
10988                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10989                     html : 'Edit'
10990                 },
10991                 {
10992                     tag : 'button',
10993                     type : 'button',
10994                     name : 'ok',
10995                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
10996                     html : 'Done'
10997                 },
10998                 {
10999                     tag : 'button',
11000                     type : 'button',
11001                     name : 'cancel',
11002                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11003                     html : 'Cancel'
11004                 }
11005             ]
11006         };
11007         
11008         if(this.editable){
11009             buttons.cn.unshift({
11010                 tag: 'input',
11011                 cls: 'select2-search-field-input'
11012             });
11013         }
11014         
11015         var _this = this;
11016         
11017         Roo.each(buttons.cn, function(c){
11018             if (_this.size) {
11019                 c.cls += ' btn-' + _this.size;
11020             }
11021
11022             if (_this.disabled) {
11023                 c.disabled = true;
11024             }
11025         });
11026         
11027         var box = {
11028             tag: 'div',
11029             cn: [
11030                 {
11031                     tag: 'input',
11032                     type : 'hidden',
11033                     cls: 'form-hidden-field'
11034                 },
11035                 {
11036                     tag: 'ul',
11037                     cls: 'select2-choices',
11038                     cn:[
11039                         {
11040                             tag: 'li',
11041                             cls: 'select2-search-field',
11042                             cn: [
11043
11044                                 buttons
11045                             ]
11046                         }
11047                     ]
11048                 }
11049             ]
11050         }
11051         
11052         var combobox = {
11053             cls: 'select2-container input-group select2-container-multi',
11054             cn: [
11055                 box
11056 //                {
11057 //                    tag: 'ul',
11058 //                    cls: 'typeahead typeahead-long dropdown-menu',
11059 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
11060 //                }
11061             ]
11062         };
11063         
11064         if(this.hasFeedback && !this.allowBlank){
11065             
11066             var feedback = {
11067                 tag: 'span',
11068                 cls: 'glyphicon form-control-feedback'
11069             };
11070
11071             combobox.cn.push(feedback);
11072         }
11073         
11074         if (align ==='left' && this.fieldLabel.length) {
11075             
11076                 Roo.log("left and has label");
11077                 cfg.cn = [
11078                     
11079                     {
11080                         tag: 'label',
11081                         'for' :  id,
11082                         cls : 'control-label col-sm-' + this.labelWidth,
11083                         html : this.fieldLabel
11084                         
11085                     },
11086                     {
11087                         cls : "col-sm-" + (12 - this.labelWidth), 
11088                         cn: [
11089                             combobox
11090                         ]
11091                     }
11092                     
11093                 ];
11094         } else if ( this.fieldLabel.length) {
11095                 Roo.log(" label");
11096                  cfg.cn = [
11097                    
11098                     {
11099                         tag: 'label',
11100                         //cls : 'input-group-addon',
11101                         html : this.fieldLabel
11102                         
11103                     },
11104                     
11105                     combobox
11106                     
11107                 ];
11108
11109         } else {
11110             
11111                 Roo.log(" no label && no align");
11112                 cfg = combobox
11113                      
11114                 
11115         }
11116          
11117         var settings=this;
11118         ['xs','sm','md','lg'].map(function(size){
11119             if (settings[size]) {
11120                 cfg.cls += ' col-' + size + '-' + settings[size];
11121             }
11122         });
11123         
11124         return cfg;
11125         
11126     },
11127     
11128     // private
11129     initEvents: function()
11130     {
11131         
11132         if (!this.store) {
11133             throw "can not find store for combo";
11134         }
11135         this.store = Roo.factory(this.store, Roo.data);
11136         
11137         if(this.tickable){
11138             this.initTickableEvents();
11139             return;
11140         }
11141         
11142         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11143         
11144         if(this.hiddenName){
11145             
11146             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11147             
11148             this.hiddenField.dom.value =
11149                 this.hiddenValue !== undefined ? this.hiddenValue :
11150                 this.value !== undefined ? this.value : '';
11151
11152             // prevent input submission
11153             this.el.dom.removeAttribute('name');
11154             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11155              
11156              
11157         }
11158         //if(Roo.isGecko){
11159         //    this.el.dom.setAttribute('autocomplete', 'off');
11160         //}
11161         
11162         var cls = 'x-combo-list';
11163         
11164         //this.list = new Roo.Layer({
11165         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11166         //});
11167         
11168         var _this = this;
11169         
11170         (function(){
11171             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11172             _this.list.setWidth(lw);
11173         }).defer(100);
11174         
11175         this.list.on('mouseover', this.onViewOver, this);
11176         this.list.on('mousemove', this.onViewMove, this);
11177         
11178         this.list.on('scroll', this.onViewScroll, this);
11179         
11180         /*
11181         this.list.swallowEvent('mousewheel');
11182         this.assetHeight = 0;
11183
11184         if(this.title){
11185             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11186             this.assetHeight += this.header.getHeight();
11187         }
11188
11189         this.innerList = this.list.createChild({cls:cls+'-inner'});
11190         this.innerList.on('mouseover', this.onViewOver, this);
11191         this.innerList.on('mousemove', this.onViewMove, this);
11192         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11193         
11194         if(this.allowBlank && !this.pageSize && !this.disableClear){
11195             this.footer = this.list.createChild({cls:cls+'-ft'});
11196             this.pageTb = new Roo.Toolbar(this.footer);
11197            
11198         }
11199         if(this.pageSize){
11200             this.footer = this.list.createChild({cls:cls+'-ft'});
11201             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11202                     {pageSize: this.pageSize});
11203             
11204         }
11205         
11206         if (this.pageTb && this.allowBlank && !this.disableClear) {
11207             var _this = this;
11208             this.pageTb.add(new Roo.Toolbar.Fill(), {
11209                 cls: 'x-btn-icon x-btn-clear',
11210                 text: '&#160;',
11211                 handler: function()
11212                 {
11213                     _this.collapse();
11214                     _this.clearValue();
11215                     _this.onSelect(false, -1);
11216                 }
11217             });
11218         }
11219         if (this.footer) {
11220             this.assetHeight += this.footer.getHeight();
11221         }
11222         */
11223             
11224         if(!this.tpl){
11225             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11226         }
11227
11228         this.view = new Roo.View(this.list, this.tpl, {
11229             singleSelect:true, store: this.store, selectedClass: this.selectedClass
11230         });
11231         //this.view.wrapEl.setDisplayed(false);
11232         this.view.on('click', this.onViewClick, this);
11233         
11234         
11235         
11236         this.store.on('beforeload', this.onBeforeLoad, this);
11237         this.store.on('load', this.onLoad, this);
11238         this.store.on('loadexception', this.onLoadException, this);
11239         /*
11240         if(this.resizable){
11241             this.resizer = new Roo.Resizable(this.list,  {
11242                pinned:true, handles:'se'
11243             });
11244             this.resizer.on('resize', function(r, w, h){
11245                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11246                 this.listWidth = w;
11247                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11248                 this.restrictHeight();
11249             }, this);
11250             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11251         }
11252         */
11253         if(!this.editable){
11254             this.editable = true;
11255             this.setEditable(false);
11256         }
11257         
11258         /*
11259         
11260         if (typeof(this.events.add.listeners) != 'undefined') {
11261             
11262             this.addicon = this.wrap.createChild(
11263                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
11264        
11265             this.addicon.on('click', function(e) {
11266                 this.fireEvent('add', this);
11267             }, this);
11268         }
11269         if (typeof(this.events.edit.listeners) != 'undefined') {
11270             
11271             this.editicon = this.wrap.createChild(
11272                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
11273             if (this.addicon) {
11274                 this.editicon.setStyle('margin-left', '40px');
11275             }
11276             this.editicon.on('click', function(e) {
11277                 
11278                 // we fire even  if inothing is selected..
11279                 this.fireEvent('edit', this, this.lastData );
11280                 
11281             }, this);
11282         }
11283         */
11284         
11285         this.keyNav = new Roo.KeyNav(this.inputEl(), {
11286             "up" : function(e){
11287                 this.inKeyMode = true;
11288                 this.selectPrev();
11289             },
11290
11291             "down" : function(e){
11292                 if(!this.isExpanded()){
11293                     this.onTriggerClick();
11294                 }else{
11295                     this.inKeyMode = true;
11296                     this.selectNext();
11297                 }
11298             },
11299
11300             "enter" : function(e){
11301 //                this.onViewClick();
11302                 //return true;
11303                 this.collapse();
11304                 
11305                 if(this.fireEvent("specialkey", this, e)){
11306                     this.onViewClick(false);
11307                 }
11308                 
11309                 return true;
11310             },
11311
11312             "esc" : function(e){
11313                 this.collapse();
11314             },
11315
11316             "tab" : function(e){
11317                 this.collapse();
11318                 
11319                 if(this.fireEvent("specialkey", this, e)){
11320                     this.onViewClick(false);
11321                 }
11322                 
11323                 return true;
11324             },
11325
11326             scope : this,
11327
11328             doRelay : function(foo, bar, hname){
11329                 if(hname == 'down' || this.scope.isExpanded()){
11330                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11331                 }
11332                 return true;
11333             },
11334
11335             forceKeyDown: true
11336         });
11337         
11338         
11339         this.queryDelay = Math.max(this.queryDelay || 10,
11340                 this.mode == 'local' ? 10 : 250);
11341         
11342         
11343         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11344         
11345         if(this.typeAhead){
11346             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11347         }
11348         if(this.editable !== false){
11349             this.inputEl().on("keyup", this.onKeyUp, this);
11350         }
11351         if(this.forceSelection){
11352             this.inputEl().on('blur', this.doForce, this);
11353         }
11354         
11355         if(this.multiple){
11356             this.choices = this.el.select('ul.select2-choices', true).first();
11357             this.searchField = this.el.select('ul li.select2-search-field', true).first();
11358         }
11359     },
11360     
11361     initTickableEvents: function()
11362     {   
11363         this.createList();
11364         
11365         if(this.hiddenName){
11366             
11367             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11368             
11369             this.hiddenField.dom.value =
11370                 this.hiddenValue !== undefined ? this.hiddenValue :
11371                 this.value !== undefined ? this.value : '';
11372
11373             // prevent input submission
11374             this.el.dom.removeAttribute('name');
11375             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11376              
11377              
11378         }
11379         
11380 //        this.list = this.el.select('ul.dropdown-menu',true).first();
11381         
11382         this.choices = this.el.select('ul.select2-choices', true).first();
11383         this.searchField = this.el.select('ul li.select2-search-field', true).first();
11384         if(this.triggerList){
11385             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11386         }
11387          
11388         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11389         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11390         
11391         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11392         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11393         
11394         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11395         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11396         
11397         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11398         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11399         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11400         
11401         this.okBtn.hide();
11402         this.cancelBtn.hide();
11403         
11404         var _this = this;
11405         
11406         (function(){
11407             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11408             _this.list.setWidth(lw);
11409         }).defer(100);
11410         
11411         this.list.on('mouseover', this.onViewOver, this);
11412         this.list.on('mousemove', this.onViewMove, this);
11413         
11414         this.list.on('scroll', this.onViewScroll, this);
11415         
11416         if(!this.tpl){
11417             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>';
11418         }
11419
11420         this.view = new Roo.View(this.list, this.tpl, {
11421             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11422         });
11423         
11424         //this.view.wrapEl.setDisplayed(false);
11425         this.view.on('click', this.onViewClick, this);
11426         
11427         
11428         
11429         this.store.on('beforeload', this.onBeforeLoad, this);
11430         this.store.on('load', this.onLoad, this);
11431         this.store.on('loadexception', this.onLoadException, this);
11432         
11433         if(this.editable){
11434             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11435                 "up" : function(e){
11436                     this.inKeyMode = true;
11437                     this.selectPrev();
11438                 },
11439
11440                 "down" : function(e){
11441                     this.inKeyMode = true;
11442                     this.selectNext();
11443                 },
11444
11445                 "enter" : function(e){
11446                     if(this.fireEvent("specialkey", this, e)){
11447                         this.onViewClick(false);
11448                     }
11449                     
11450                     return true;
11451                 },
11452
11453                 "esc" : function(e){
11454                     this.onTickableFooterButtonClick(e, false, false);
11455                 },
11456
11457                 "tab" : function(e){
11458                     this.fireEvent("specialkey", this, e);
11459                     
11460                     this.onTickableFooterButtonClick(e, false, false);
11461                     
11462                     return true;
11463                 },
11464
11465                 scope : this,
11466
11467                 doRelay : function(e, fn, key){
11468                     if(this.scope.isExpanded()){
11469                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11470                     }
11471                     return true;
11472                 },
11473
11474                 forceKeyDown: true
11475             });
11476         }
11477         
11478         this.queryDelay = Math.max(this.queryDelay || 10,
11479                 this.mode == 'local' ? 10 : 250);
11480         
11481         
11482         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11483         
11484         if(this.typeAhead){
11485             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11486         }
11487         
11488         if(this.editable !== false){
11489             this.tickableInputEl().on("keyup", this.onKeyUp, this);
11490         }
11491         
11492     },
11493
11494     onDestroy : function(){
11495         if(this.view){
11496             this.view.setStore(null);
11497             this.view.el.removeAllListeners();
11498             this.view.el.remove();
11499             this.view.purgeListeners();
11500         }
11501         if(this.list){
11502             this.list.dom.innerHTML  = '';
11503         }
11504         
11505         if(this.store){
11506             this.store.un('beforeload', this.onBeforeLoad, this);
11507             this.store.un('load', this.onLoad, this);
11508             this.store.un('loadexception', this.onLoadException, this);
11509         }
11510         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11511     },
11512
11513     // private
11514     fireKey : function(e){
11515         if(e.isNavKeyPress() && !this.list.isVisible()){
11516             this.fireEvent("specialkey", this, e);
11517         }
11518     },
11519
11520     // private
11521     onResize: function(w, h){
11522 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11523 //        
11524 //        if(typeof w != 'number'){
11525 //            // we do not handle it!?!?
11526 //            return;
11527 //        }
11528 //        var tw = this.trigger.getWidth();
11529 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
11530 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
11531 //        var x = w - tw;
11532 //        this.inputEl().setWidth( this.adjustWidth('input', x));
11533 //            
11534 //        //this.trigger.setStyle('left', x+'px');
11535 //        
11536 //        if(this.list && this.listWidth === undefined){
11537 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11538 //            this.list.setWidth(lw);
11539 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11540 //        }
11541         
11542     
11543         
11544     },
11545
11546     /**
11547      * Allow or prevent the user from directly editing the field text.  If false is passed,
11548      * the user will only be able to select from the items defined in the dropdown list.  This method
11549      * is the runtime equivalent of setting the 'editable' config option at config time.
11550      * @param {Boolean} value True to allow the user to directly edit the field text
11551      */
11552     setEditable : function(value){
11553         if(value == this.editable){
11554             return;
11555         }
11556         this.editable = value;
11557         if(!value){
11558             this.inputEl().dom.setAttribute('readOnly', true);
11559             this.inputEl().on('mousedown', this.onTriggerClick,  this);
11560             this.inputEl().addClass('x-combo-noedit');
11561         }else{
11562             this.inputEl().dom.setAttribute('readOnly', false);
11563             this.inputEl().un('mousedown', this.onTriggerClick,  this);
11564             this.inputEl().removeClass('x-combo-noedit');
11565         }
11566     },
11567
11568     // private
11569     
11570     onBeforeLoad : function(combo,opts){
11571         if(!this.hasFocus){
11572             return;
11573         }
11574          if (!opts.add) {
11575             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11576          }
11577         this.restrictHeight();
11578         this.selectedIndex = -1;
11579     },
11580
11581     // private
11582     onLoad : function(){
11583         
11584         this.hasQuery = false;
11585         
11586         if(!this.hasFocus){
11587             return;
11588         }
11589         
11590         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11591             this.loading.hide();
11592         }
11593              
11594         if(this.store.getCount() > 0){
11595             this.expand();
11596             this.restrictHeight();
11597             if(this.lastQuery == this.allQuery){
11598                 if(this.editable && !this.tickable){
11599                     this.inputEl().dom.select();
11600                 }
11601                 
11602                 if(
11603                     !this.selectByValue(this.value, true) &&
11604                     this.autoFocus && 
11605                     (
11606                         !this.store.lastOptions ||
11607                         typeof(this.store.lastOptions.add) == 'undefined' || 
11608                         this.store.lastOptions.add != true
11609                     )
11610                 ){
11611                     this.select(0, true);
11612                 }
11613             }else{
11614                 if(this.autoFocus){
11615                     this.selectNext();
11616                 }
11617                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11618                     this.taTask.delay(this.typeAheadDelay);
11619                 }
11620             }
11621         }else{
11622             this.onEmptyResults();
11623         }
11624         
11625         //this.el.focus();
11626     },
11627     // private
11628     onLoadException : function()
11629     {
11630         this.hasQuery = false;
11631         
11632         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11633             this.loading.hide();
11634         }
11635         
11636         if(this.tickable && this.editable){
11637             return;
11638         }
11639         
11640         this.collapse();
11641         
11642         Roo.log(this.store.reader.jsonData);
11643         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11644             // fixme
11645             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11646         }
11647         
11648         
11649     },
11650     // private
11651     onTypeAhead : function(){
11652         if(this.store.getCount() > 0){
11653             var r = this.store.getAt(0);
11654             var newValue = r.data[this.displayField];
11655             var len = newValue.length;
11656             var selStart = this.getRawValue().length;
11657             
11658             if(selStart != len){
11659                 this.setRawValue(newValue);
11660                 this.selectText(selStart, newValue.length);
11661             }
11662         }
11663     },
11664
11665     // private
11666     onSelect : function(record, index){
11667         
11668         if(this.fireEvent('beforeselect', this, record, index) !== false){
11669         
11670             this.setFromData(index > -1 ? record.data : false);
11671             
11672             this.collapse();
11673             this.fireEvent('select', this, record, index);
11674         }
11675     },
11676
11677     /**
11678      * Returns the currently selected field value or empty string if no value is set.
11679      * @return {String} value The selected value
11680      */
11681     getValue : function(){
11682         
11683         if(this.multiple){
11684             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11685         }
11686         
11687         if(this.valueField){
11688             return typeof this.value != 'undefined' ? this.value : '';
11689         }else{
11690             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11691         }
11692     },
11693
11694     /**
11695      * Clears any text/value currently set in the field
11696      */
11697     clearValue : function(){
11698         if(this.hiddenField){
11699             this.hiddenField.dom.value = '';
11700         }
11701         this.value = '';
11702         this.setRawValue('');
11703         this.lastSelectionText = '';
11704         this.lastData = false;
11705         
11706     },
11707
11708     /**
11709      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
11710      * will be displayed in the field.  If the value does not match the data value of an existing item,
11711      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11712      * Otherwise the field will be blank (although the value will still be set).
11713      * @param {String} value The value to match
11714      */
11715     setValue : function(v){
11716         if(this.multiple){
11717             this.syncValue();
11718             return;
11719         }
11720         
11721         var text = v;
11722         if(this.valueField){
11723             var r = this.findRecord(this.valueField, v);
11724             if(r){
11725                 text = r.data[this.displayField];
11726             }else if(this.valueNotFoundText !== undefined){
11727                 text = this.valueNotFoundText;
11728             }
11729         }
11730         this.lastSelectionText = text;
11731         if(this.hiddenField){
11732             this.hiddenField.dom.value = v;
11733         }
11734         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11735         this.value = v;
11736     },
11737     /**
11738      * @property {Object} the last set data for the element
11739      */
11740     
11741     lastData : false,
11742     /**
11743      * Sets the value of the field based on a object which is related to the record format for the store.
11744      * @param {Object} value the value to set as. or false on reset?
11745      */
11746     setFromData : function(o){
11747         
11748         if(this.multiple){
11749             this.addItem(o);
11750             return;
11751         }
11752             
11753         var dv = ''; // display value
11754         var vv = ''; // value value..
11755         this.lastData = o;
11756         if (this.displayField) {
11757             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11758         } else {
11759             // this is an error condition!!!
11760             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11761         }
11762         
11763         if(this.valueField){
11764             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11765         }
11766         
11767         if(this.hiddenField){
11768             this.hiddenField.dom.value = vv;
11769             
11770             this.lastSelectionText = dv;
11771             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11772             this.value = vv;
11773             return;
11774         }
11775         // no hidden field.. - we store the value in 'value', but still display
11776         // display field!!!!
11777         this.lastSelectionText = dv;
11778         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11779         this.value = vv;
11780         
11781         
11782     },
11783     // private
11784     reset : function(){
11785         // overridden so that last data is reset..
11786         
11787         if(this.multiple){
11788             this.clearItem();
11789             return;
11790         }
11791         
11792         this.setValue(this.originalValue);
11793         this.clearInvalid();
11794         this.lastData = false;
11795         if (this.view) {
11796             this.view.clearSelections();
11797         }
11798     },
11799     // private
11800     findRecord : function(prop, value){
11801         var record;
11802         if(this.store.getCount() > 0){
11803             this.store.each(function(r){
11804                 if(r.data[prop] == value){
11805                     record = r;
11806                     return false;
11807                 }
11808                 return true;
11809             });
11810         }
11811         return record;
11812     },
11813     
11814     getName: function()
11815     {
11816         // returns hidden if it's set..
11817         if (!this.rendered) {return ''};
11818         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
11819         
11820     },
11821     // private
11822     onViewMove : function(e, t){
11823         this.inKeyMode = false;
11824     },
11825
11826     // private
11827     onViewOver : function(e, t){
11828         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11829             return;
11830         }
11831         var item = this.view.findItemFromChild(t);
11832         
11833         if(item){
11834             var index = this.view.indexOf(item);
11835             this.select(index, false);
11836         }
11837     },
11838
11839     // private
11840     onViewClick : function(view, doFocus, el, e)
11841     {
11842         var index = this.view.getSelectedIndexes()[0];
11843         
11844         var r = this.store.getAt(index);
11845         
11846         if(this.tickable){
11847             
11848             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11849                 return;
11850             }
11851             
11852             var rm = false;
11853             var _this = this;
11854             
11855             Roo.each(this.tickItems, function(v,k){
11856                 
11857                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11858                     _this.tickItems.splice(k, 1);
11859                     
11860                     if(typeof(e) == 'undefined' && view == false){
11861                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11862                     }
11863                     
11864                     rm = true;
11865                     return;
11866                 }
11867             });
11868             
11869             if(rm){
11870                 return;
11871             }
11872             
11873             this.tickItems.push(r.data);
11874             
11875             if(typeof(e) == 'undefined' && view == false){
11876                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11877             }
11878                     
11879             return;
11880         }
11881         
11882         if(r){
11883             this.onSelect(r, index);
11884         }
11885         if(doFocus !== false && !this.blockFocus){
11886             this.inputEl().focus();
11887         }
11888     },
11889
11890     // private
11891     restrictHeight : function(){
11892         //this.innerList.dom.style.height = '';
11893         //var inner = this.innerList.dom;
11894         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11895         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11896         //this.list.beginUpdate();
11897         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11898         this.list.alignTo(this.inputEl(), this.listAlign);
11899         this.list.alignTo(this.inputEl(), this.listAlign);
11900         //this.list.endUpdate();
11901     },
11902
11903     // private
11904     onEmptyResults : function(){
11905         
11906         if(this.tickable && this.editable){
11907             this.restrictHeight();
11908             return;
11909         }
11910         
11911         this.collapse();
11912     },
11913
11914     /**
11915      * Returns true if the dropdown list is expanded, else false.
11916      */
11917     isExpanded : function(){
11918         return this.list.isVisible();
11919     },
11920
11921     /**
11922      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11923      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11924      * @param {String} value The data value of the item to select
11925      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11926      * selected item if it is not currently in view (defaults to true)
11927      * @return {Boolean} True if the value matched an item in the list, else false
11928      */
11929     selectByValue : function(v, scrollIntoView){
11930         if(v !== undefined && v !== null){
11931             var r = this.findRecord(this.valueField || this.displayField, v);
11932             if(r){
11933                 this.select(this.store.indexOf(r), scrollIntoView);
11934                 return true;
11935             }
11936         }
11937         return false;
11938     },
11939
11940     /**
11941      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11942      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11943      * @param {Number} index The zero-based index of the list item to select
11944      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11945      * selected item if it is not currently in view (defaults to true)
11946      */
11947     select : function(index, scrollIntoView){
11948         this.selectedIndex = index;
11949         this.view.select(index);
11950         if(scrollIntoView !== false){
11951             var el = this.view.getNode(index);
11952             /*
11953              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
11954              */
11955             if(el){
11956                 this.list.scrollChildIntoView(el, false);
11957             }
11958         }
11959     },
11960
11961     // private
11962     selectNext : function(){
11963         var ct = this.store.getCount();
11964         if(ct > 0){
11965             if(this.selectedIndex == -1){
11966                 this.select(0);
11967             }else if(this.selectedIndex < ct-1){
11968                 this.select(this.selectedIndex+1);
11969             }
11970         }
11971     },
11972
11973     // private
11974     selectPrev : function(){
11975         var ct = this.store.getCount();
11976         if(ct > 0){
11977             if(this.selectedIndex == -1){
11978                 this.select(0);
11979             }else if(this.selectedIndex != 0){
11980                 this.select(this.selectedIndex-1);
11981             }
11982         }
11983     },
11984
11985     // private
11986     onKeyUp : function(e){
11987         if(this.editable !== false && !e.isSpecialKey()){
11988             this.lastKey = e.getKey();
11989             this.dqTask.delay(this.queryDelay);
11990         }
11991     },
11992
11993     // private
11994     validateBlur : function(){
11995         return !this.list || !this.list.isVisible();   
11996     },
11997
11998     // private
11999     initQuery : function(){
12000         
12001         var v = this.getRawValue();
12002         
12003         if(this.tickable && this.editable){
12004             v = this.tickableInputEl().getValue();
12005         }
12006         
12007         this.doQuery(v);
12008     },
12009
12010     // private
12011     doForce : function(){
12012         if(this.inputEl().dom.value.length > 0){
12013             this.inputEl().dom.value =
12014                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12015              
12016         }
12017     },
12018
12019     /**
12020      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
12021      * query allowing the query action to be canceled if needed.
12022      * @param {String} query The SQL query to execute
12023      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12024      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
12025      * saved in the current store (defaults to false)
12026      */
12027     doQuery : function(q, forceAll){
12028         
12029         if(q === undefined || q === null){
12030             q = '';
12031         }
12032         var qe = {
12033             query: q,
12034             forceAll: forceAll,
12035             combo: this,
12036             cancel:false
12037         };
12038         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12039             return false;
12040         }
12041         q = qe.query;
12042         
12043         forceAll = qe.forceAll;
12044         if(forceAll === true || (q.length >= this.minChars)){
12045             
12046             this.hasQuery = true;
12047             
12048             if(this.lastQuery != q || this.alwaysQuery){
12049                 this.lastQuery = q;
12050                 if(this.mode == 'local'){
12051                     this.selectedIndex = -1;
12052                     if(forceAll){
12053                         this.store.clearFilter();
12054                     }else{
12055                         this.store.filter(this.displayField, q);
12056                     }
12057                     this.onLoad();
12058                 }else{
12059                     
12060                     this.store.baseParams[this.queryParam] = q;
12061                     
12062                     var options = {params : this.getParams(q)};
12063                     
12064                     if(this.loadNext){
12065                         options.add = true;
12066                         options.params.start = this.page * this.pageSize;
12067                     }
12068                     
12069                     this.store.load(options);
12070                     
12071                     /*
12072                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
12073                      *  we should expand the list on onLoad
12074                      *  so command out it
12075                      */
12076 //                    this.expand();
12077                 }
12078             }else{
12079                 this.selectedIndex = -1;
12080                 this.onLoad();   
12081             }
12082         }
12083         
12084         this.loadNext = false;
12085     },
12086
12087     // private
12088     getParams : function(q){
12089         var p = {};
12090         //p[this.queryParam] = q;
12091         
12092         if(this.pageSize){
12093             p.start = 0;
12094             p.limit = this.pageSize;
12095         }
12096         return p;
12097     },
12098
12099     /**
12100      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12101      */
12102     collapse : function(){
12103         if(!this.isExpanded()){
12104             return;
12105         }
12106         
12107         this.list.hide();
12108         
12109         if(this.tickable){
12110             this.hasFocus = false;
12111             this.okBtn.hide();
12112             this.cancelBtn.hide();
12113             this.trigger.show();
12114             
12115             if(this.editable){
12116                 this.tickableInputEl().dom.value = '';
12117                 this.tickableInputEl().blur();
12118             }
12119             
12120         }
12121         
12122         Roo.get(document).un('mousedown', this.collapseIf, this);
12123         Roo.get(document).un('mousewheel', this.collapseIf, this);
12124         if (!this.editable) {
12125             Roo.get(document).un('keydown', this.listKeyPress, this);
12126         }
12127         this.fireEvent('collapse', this);
12128     },
12129
12130     // private
12131     collapseIf : function(e){
12132         var in_combo  = e.within(this.el);
12133         var in_list =  e.within(this.list);
12134         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12135         
12136         if (in_combo || in_list || is_list) {
12137             //e.stopPropagation();
12138             return;
12139         }
12140         
12141         if(this.tickable){
12142             this.onTickableFooterButtonClick(e, false, false);
12143         }
12144
12145         this.collapse();
12146         
12147     },
12148
12149     /**
12150      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12151      */
12152     expand : function(){
12153        
12154         if(this.isExpanded() || !this.hasFocus){
12155             return;
12156         }
12157         
12158         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12159         this.list.setWidth(lw);
12160         
12161         
12162          Roo.log('expand');
12163         
12164         this.list.show();
12165         
12166         this.restrictHeight();
12167         
12168         if(this.tickable){
12169             
12170             this.tickItems = Roo.apply([], this.item);
12171             
12172             this.okBtn.show();
12173             this.cancelBtn.show();
12174             this.trigger.hide();
12175             
12176             if(this.editable){
12177                 this.tickableInputEl().focus();
12178             }
12179             
12180         }
12181         
12182         Roo.get(document).on('mousedown', this.collapseIf, this);
12183         Roo.get(document).on('mousewheel', this.collapseIf, this);
12184         if (!this.editable) {
12185             Roo.get(document).on('keydown', this.listKeyPress, this);
12186         }
12187         
12188         this.fireEvent('expand', this);
12189     },
12190
12191     // private
12192     // Implements the default empty TriggerField.onTriggerClick function
12193     onTriggerClick : function(e)
12194     {
12195         Roo.log('trigger click');
12196         
12197         if(this.disabled || !this.triggerList){
12198             return;
12199         }
12200         
12201         this.page = 0;
12202         this.loadNext = false;
12203         
12204         if(this.isExpanded()){
12205             this.collapse();
12206             if (!this.blockFocus) {
12207                 this.inputEl().focus();
12208             }
12209             
12210         }else {
12211             this.hasFocus = true;
12212             if(this.triggerAction == 'all') {
12213                 this.doQuery(this.allQuery, true);
12214             } else {
12215                 this.doQuery(this.getRawValue());
12216             }
12217             if (!this.blockFocus) {
12218                 this.inputEl().focus();
12219             }
12220         }
12221     },
12222     
12223     onTickableTriggerClick : function(e)
12224     {
12225         if(this.disabled){
12226             return;
12227         }
12228         
12229         this.page = 0;
12230         this.loadNext = false;
12231         this.hasFocus = true;
12232         
12233         if(this.triggerAction == 'all') {
12234             this.doQuery(this.allQuery, true);
12235         } else {
12236             this.doQuery(this.getRawValue());
12237         }
12238     },
12239     
12240     onSearchFieldClick : function(e)
12241     {
12242         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12243             this.onTickableFooterButtonClick(e, false, false);
12244             return;
12245         }
12246         
12247         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12248             return;
12249         }
12250         
12251         this.page = 0;
12252         this.loadNext = false;
12253         this.hasFocus = true;
12254         
12255         if(this.triggerAction == 'all') {
12256             this.doQuery(this.allQuery, true);
12257         } else {
12258             this.doQuery(this.getRawValue());
12259         }
12260     },
12261     
12262     listKeyPress : function(e)
12263     {
12264         //Roo.log('listkeypress');
12265         // scroll to first matching element based on key pres..
12266         if (e.isSpecialKey()) {
12267             return false;
12268         }
12269         var k = String.fromCharCode(e.getKey()).toUpperCase();
12270         //Roo.log(k);
12271         var match  = false;
12272         var csel = this.view.getSelectedNodes();
12273         var cselitem = false;
12274         if (csel.length) {
12275             var ix = this.view.indexOf(csel[0]);
12276             cselitem  = this.store.getAt(ix);
12277             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12278                 cselitem = false;
12279             }
12280             
12281         }
12282         
12283         this.store.each(function(v) { 
12284             if (cselitem) {
12285                 // start at existing selection.
12286                 if (cselitem.id == v.id) {
12287                     cselitem = false;
12288                 }
12289                 return true;
12290             }
12291                 
12292             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12293                 match = this.store.indexOf(v);
12294                 return false;
12295             }
12296             return true;
12297         }, this);
12298         
12299         if (match === false) {
12300             return true; // no more action?
12301         }
12302         // scroll to?
12303         this.view.select(match);
12304         var sn = Roo.get(this.view.getSelectedNodes()[0])
12305         sn.scrollIntoView(sn.dom.parentNode, false);
12306     },
12307     
12308     onViewScroll : function(e, t){
12309         
12310         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){
12311             return;
12312         }
12313         
12314         this.hasQuery = true;
12315         
12316         this.loading = this.list.select('.loading', true).first();
12317         
12318         if(this.loading === null){
12319             this.list.createChild({
12320                 tag: 'div',
12321                 cls: 'loading select2-more-results select2-active',
12322                 html: 'Loading more results...'
12323             })
12324             
12325             this.loading = this.list.select('.loading', true).first();
12326             
12327             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12328             
12329             this.loading.hide();
12330         }
12331         
12332         this.loading.show();
12333         
12334         var _combo = this;
12335         
12336         this.page++;
12337         this.loadNext = true;
12338         
12339         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12340         
12341         return;
12342     },
12343     
12344     addItem : function(o)
12345     {   
12346         var dv = ''; // display value
12347         
12348         if (this.displayField) {
12349             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12350         } else {
12351             // this is an error condition!!!
12352             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
12353         }
12354         
12355         if(!dv.length){
12356             return;
12357         }
12358         
12359         var choice = this.choices.createChild({
12360             tag: 'li',
12361             cls: 'select2-search-choice',
12362             cn: [
12363                 {
12364                     tag: 'div',
12365                     html: dv
12366                 },
12367                 {
12368                     tag: 'a',
12369                     href: '#',
12370                     cls: 'select2-search-choice-close',
12371                     tabindex: '-1'
12372                 }
12373             ]
12374             
12375         }, this.searchField);
12376         
12377         var close = choice.select('a.select2-search-choice-close', true).first()
12378         
12379         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12380         
12381         this.item.push(o);
12382         
12383         this.lastData = o;
12384         
12385         this.syncValue();
12386         
12387         this.inputEl().dom.value = '';
12388         
12389         this.validate();
12390     },
12391     
12392     onRemoveItem : function(e, _self, o)
12393     {
12394         e.preventDefault();
12395         
12396         this.lastItem = Roo.apply([], this.item);
12397         
12398         var index = this.item.indexOf(o.data) * 1;
12399         
12400         if( index < 0){
12401             Roo.log('not this item?!');
12402             return;
12403         }
12404         
12405         this.item.splice(index, 1);
12406         o.item.remove();
12407         
12408         this.syncValue();
12409         
12410         this.fireEvent('remove', this, e);
12411         
12412         this.validate();
12413         
12414     },
12415     
12416     syncValue : function()
12417     {
12418         if(!this.item.length){
12419             this.clearValue();
12420             return;
12421         }
12422             
12423         var value = [];
12424         var _this = this;
12425         Roo.each(this.item, function(i){
12426             if(_this.valueField){
12427                 value.push(i[_this.valueField]);
12428                 return;
12429             }
12430
12431             value.push(i);
12432         });
12433
12434         this.value = value.join(',');
12435
12436         if(this.hiddenField){
12437             this.hiddenField.dom.value = this.value;
12438         }
12439     },
12440     
12441     clearItem : function()
12442     {
12443         if(!this.multiple){
12444             return;
12445         }
12446         
12447         this.item = [];
12448         
12449         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12450            c.remove();
12451         });
12452         
12453         this.syncValue();
12454         
12455         this.validate();
12456     },
12457     
12458     inputEl: function ()
12459     {
12460         if(this.tickable){
12461             return this.searchField;
12462         }
12463         return this.el.select('input.form-control',true).first();
12464     },
12465     
12466     
12467     onTickableFooterButtonClick : function(e, btn, el)
12468     {
12469         e.preventDefault();
12470         
12471         this.lastItem = Roo.apply([], this.item);
12472         
12473         if(btn && btn.name == 'cancel'){
12474             this.tickItems = Roo.apply([], this.item);
12475             this.collapse();
12476             return;
12477         }
12478         
12479         this.clearItem();
12480         
12481         var _this = this;
12482         
12483         Roo.each(this.tickItems, function(o){
12484             _this.addItem(o);
12485         });
12486         
12487         this.collapse();
12488         
12489     },
12490     
12491     validate : function()
12492     {
12493         var v = this.getRawValue();
12494         
12495         if(this.multiple){
12496             v = this.getValue();
12497         }
12498         
12499         if(this.disabled || this.allowBlank || v.length){
12500             this.markValid();
12501             return true;
12502         }
12503         
12504         this.markInvalid();
12505         return false;
12506     },
12507     
12508     tickableInputEl : function()
12509     {
12510         if(!this.tickable || !this.editable){
12511             return this.inputEl();
12512         }
12513         
12514         return this.inputEl().select('.select2-search-field-input', true).first();
12515     }
12516     
12517     
12518
12519     /** 
12520     * @cfg {Boolean} grow 
12521     * @hide 
12522     */
12523     /** 
12524     * @cfg {Number} growMin 
12525     * @hide 
12526     */
12527     /** 
12528     * @cfg {Number} growMax 
12529     * @hide 
12530     */
12531     /**
12532      * @hide
12533      * @method autoSize
12534      */
12535 });
12536 /*
12537  * Based on:
12538  * Ext JS Library 1.1.1
12539  * Copyright(c) 2006-2007, Ext JS, LLC.
12540  *
12541  * Originally Released Under LGPL - original licence link has changed is not relivant.
12542  *
12543  * Fork - LGPL
12544  * <script type="text/javascript">
12545  */
12546
12547 /**
12548  * @class Roo.View
12549  * @extends Roo.util.Observable
12550  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
12551  * This class also supports single and multi selection modes. <br>
12552  * Create a data model bound view:
12553  <pre><code>
12554  var store = new Roo.data.Store(...);
12555
12556  var view = new Roo.View({
12557     el : "my-element",
12558     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
12559  
12560     singleSelect: true,
12561     selectedClass: "ydataview-selected",
12562     store: store
12563  });
12564
12565  // listen for node click?
12566  view.on("click", function(vw, index, node, e){
12567  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12568  });
12569
12570  // load XML data
12571  dataModel.load("foobar.xml");
12572  </code></pre>
12573  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12574  * <br><br>
12575  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12576  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12577  * 
12578  * Note: old style constructor is still suported (container, template, config)
12579  * 
12580  * @constructor
12581  * Create a new View
12582  * @param {Object} config The config object
12583  * 
12584  */
12585 Roo.View = function(config, depreciated_tpl, depreciated_config){
12586     
12587     this.parent = false;
12588     
12589     if (typeof(depreciated_tpl) == 'undefined') {
12590         // new way.. - universal constructor.
12591         Roo.apply(this, config);
12592         this.el  = Roo.get(this.el);
12593     } else {
12594         // old format..
12595         this.el  = Roo.get(config);
12596         this.tpl = depreciated_tpl;
12597         Roo.apply(this, depreciated_config);
12598     }
12599     this.wrapEl  = this.el.wrap().wrap();
12600     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12601     
12602     
12603     if(typeof(this.tpl) == "string"){
12604         this.tpl = new Roo.Template(this.tpl);
12605     } else {
12606         // support xtype ctors..
12607         this.tpl = new Roo.factory(this.tpl, Roo);
12608     }
12609     
12610     
12611     this.tpl.compile();
12612     
12613     /** @private */
12614     this.addEvents({
12615         /**
12616          * @event beforeclick
12617          * Fires before a click is processed. Returns false to cancel the default action.
12618          * @param {Roo.View} this
12619          * @param {Number} index The index of the target node
12620          * @param {HTMLElement} node The target node
12621          * @param {Roo.EventObject} e The raw event object
12622          */
12623             "beforeclick" : true,
12624         /**
12625          * @event click
12626          * Fires when a template node is clicked.
12627          * @param {Roo.View} this
12628          * @param {Number} index The index of the target node
12629          * @param {HTMLElement} node The target node
12630          * @param {Roo.EventObject} e The raw event object
12631          */
12632             "click" : true,
12633         /**
12634          * @event dblclick
12635          * Fires when a template node is double clicked.
12636          * @param {Roo.View} this
12637          * @param {Number} index The index of the target node
12638          * @param {HTMLElement} node The target node
12639          * @param {Roo.EventObject} e The raw event object
12640          */
12641             "dblclick" : true,
12642         /**
12643          * @event contextmenu
12644          * Fires when a template node is right clicked.
12645          * @param {Roo.View} this
12646          * @param {Number} index The index of the target node
12647          * @param {HTMLElement} node The target node
12648          * @param {Roo.EventObject} e The raw event object
12649          */
12650             "contextmenu" : true,
12651         /**
12652          * @event selectionchange
12653          * Fires when the selected nodes change.
12654          * @param {Roo.View} this
12655          * @param {Array} selections Array of the selected nodes
12656          */
12657             "selectionchange" : true,
12658     
12659         /**
12660          * @event beforeselect
12661          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12662          * @param {Roo.View} this
12663          * @param {HTMLElement} node The node to be selected
12664          * @param {Array} selections Array of currently selected nodes
12665          */
12666             "beforeselect" : true,
12667         /**
12668          * @event preparedata
12669          * Fires on every row to render, to allow you to change the data.
12670          * @param {Roo.View} this
12671          * @param {Object} data to be rendered (change this)
12672          */
12673           "preparedata" : true
12674           
12675           
12676         });
12677
12678
12679
12680     this.el.on({
12681         "click": this.onClick,
12682         "dblclick": this.onDblClick,
12683         "contextmenu": this.onContextMenu,
12684         scope:this
12685     });
12686
12687     this.selections = [];
12688     this.nodes = [];
12689     this.cmp = new Roo.CompositeElementLite([]);
12690     if(this.store){
12691         this.store = Roo.factory(this.store, Roo.data);
12692         this.setStore(this.store, true);
12693     }
12694     
12695     if ( this.footer && this.footer.xtype) {
12696            
12697          var fctr = this.wrapEl.appendChild(document.createElement("div"));
12698         
12699         this.footer.dataSource = this.store
12700         this.footer.container = fctr;
12701         this.footer = Roo.factory(this.footer, Roo);
12702         fctr.insertFirst(this.el);
12703         
12704         // this is a bit insane - as the paging toolbar seems to detach the el..
12705 //        dom.parentNode.parentNode.parentNode
12706          // they get detached?
12707     }
12708     
12709     
12710     Roo.View.superclass.constructor.call(this);
12711     
12712     
12713 };
12714
12715 Roo.extend(Roo.View, Roo.util.Observable, {
12716     
12717      /**
12718      * @cfg {Roo.data.Store} store Data store to load data from.
12719      */
12720     store : false,
12721     
12722     /**
12723      * @cfg {String|Roo.Element} el The container element.
12724      */
12725     el : '',
12726     
12727     /**
12728      * @cfg {String|Roo.Template} tpl The template used by this View 
12729      */
12730     tpl : false,
12731     /**
12732      * @cfg {String} dataName the named area of the template to use as the data area
12733      *                          Works with domtemplates roo-name="name"
12734      */
12735     dataName: false,
12736     /**
12737      * @cfg {String} selectedClass The css class to add to selected nodes
12738      */
12739     selectedClass : "x-view-selected",
12740      /**
12741      * @cfg {String} emptyText The empty text to show when nothing is loaded.
12742      */
12743     emptyText : "",
12744     
12745     /**
12746      * @cfg {String} text to display on mask (default Loading)
12747      */
12748     mask : false,
12749     /**
12750      * @cfg {Boolean} multiSelect Allow multiple selection
12751      */
12752     multiSelect : false,
12753     /**
12754      * @cfg {Boolean} singleSelect Allow single selection
12755      */
12756     singleSelect:  false,
12757     
12758     /**
12759      * @cfg {Boolean} toggleSelect - selecting 
12760      */
12761     toggleSelect : false,
12762     
12763     /**
12764      * @cfg {Boolean} tickable - selecting 
12765      */
12766     tickable : false,
12767     
12768     /**
12769      * Returns the element this view is bound to.
12770      * @return {Roo.Element}
12771      */
12772     getEl : function(){
12773         return this.wrapEl;
12774     },
12775     
12776     
12777
12778     /**
12779      * Refreshes the view. - called by datachanged on the store. - do not call directly.
12780      */
12781     refresh : function(){
12782         //Roo.log('refresh');
12783         var t = this.tpl;
12784         
12785         // if we are using something like 'domtemplate', then
12786         // the what gets used is:
12787         // t.applySubtemplate(NAME, data, wrapping data..)
12788         // the outer template then get' applied with
12789         //     the store 'extra data'
12790         // and the body get's added to the
12791         //      roo-name="data" node?
12792         //      <span class='roo-tpl-{name}'></span> ?????
12793         
12794         
12795         
12796         this.clearSelections();
12797         this.el.update("");
12798         var html = [];
12799         var records = this.store.getRange();
12800         if(records.length < 1) {
12801             
12802             // is this valid??  = should it render a template??
12803             
12804             this.el.update(this.emptyText);
12805             return;
12806         }
12807         var el = this.el;
12808         if (this.dataName) {
12809             this.el.update(t.apply(this.store.meta)); //????
12810             el = this.el.child('.roo-tpl-' + this.dataName);
12811         }
12812         
12813         for(var i = 0, len = records.length; i < len; i++){
12814             var data = this.prepareData(records[i].data, i, records[i]);
12815             this.fireEvent("preparedata", this, data, i, records[i]);
12816             
12817             var d = Roo.apply({}, data);
12818             
12819             if(this.tickable){
12820                 Roo.apply(d, {'roo-id' : Roo.id()});
12821                 
12822                 var _this = this;
12823             
12824                 Roo.each(this.parent.item, function(item){
12825                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12826                         return;
12827                     }
12828                     Roo.apply(d, {'roo-data-checked' : 'checked'});
12829                 });
12830             }
12831             
12832             html[html.length] = Roo.util.Format.trim(
12833                 this.dataName ?
12834                     t.applySubtemplate(this.dataName, d, this.store.meta) :
12835                     t.apply(d)
12836             );
12837         }
12838         
12839         
12840         
12841         el.update(html.join(""));
12842         this.nodes = el.dom.childNodes;
12843         this.updateIndexes(0);
12844     },
12845     
12846
12847     /**
12848      * Function to override to reformat the data that is sent to
12849      * the template for each node.
12850      * DEPRICATED - use the preparedata event handler.
12851      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12852      * a JSON object for an UpdateManager bound view).
12853      */
12854     prepareData : function(data, index, record)
12855     {
12856         this.fireEvent("preparedata", this, data, index, record);
12857         return data;
12858     },
12859
12860     onUpdate : function(ds, record){
12861         // Roo.log('on update');   
12862         this.clearSelections();
12863         var index = this.store.indexOf(record);
12864         var n = this.nodes[index];
12865         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12866         n.parentNode.removeChild(n);
12867         this.updateIndexes(index, index);
12868     },
12869
12870     
12871     
12872 // --------- FIXME     
12873     onAdd : function(ds, records, index)
12874     {
12875         //Roo.log(['on Add', ds, records, index] );        
12876         this.clearSelections();
12877         if(this.nodes.length == 0){
12878             this.refresh();
12879             return;
12880         }
12881         var n = this.nodes[index];
12882         for(var i = 0, len = records.length; i < len; i++){
12883             var d = this.prepareData(records[i].data, i, records[i]);
12884             if(n){
12885                 this.tpl.insertBefore(n, d);
12886             }else{
12887                 
12888                 this.tpl.append(this.el, d);
12889             }
12890         }
12891         this.updateIndexes(index);
12892     },
12893
12894     onRemove : function(ds, record, index){
12895        // Roo.log('onRemove');
12896         this.clearSelections();
12897         var el = this.dataName  ?
12898             this.el.child('.roo-tpl-' + this.dataName) :
12899             this.el; 
12900         
12901         el.dom.removeChild(this.nodes[index]);
12902         this.updateIndexes(index);
12903     },
12904
12905     /**
12906      * Refresh an individual node.
12907      * @param {Number} index
12908      */
12909     refreshNode : function(index){
12910         this.onUpdate(this.store, this.store.getAt(index));
12911     },
12912
12913     updateIndexes : function(startIndex, endIndex){
12914         var ns = this.nodes;
12915         startIndex = startIndex || 0;
12916         endIndex = endIndex || ns.length - 1;
12917         for(var i = startIndex; i <= endIndex; i++){
12918             ns[i].nodeIndex = i;
12919         }
12920     },
12921
12922     /**
12923      * Changes the data store this view uses and refresh the view.
12924      * @param {Store} store
12925      */
12926     setStore : function(store, initial){
12927         if(!initial && this.store){
12928             this.store.un("datachanged", this.refresh);
12929             this.store.un("add", this.onAdd);
12930             this.store.un("remove", this.onRemove);
12931             this.store.un("update", this.onUpdate);
12932             this.store.un("clear", this.refresh);
12933             this.store.un("beforeload", this.onBeforeLoad);
12934             this.store.un("load", this.onLoad);
12935             this.store.un("loadexception", this.onLoad);
12936         }
12937         if(store){
12938           
12939             store.on("datachanged", this.refresh, this);
12940             store.on("add", this.onAdd, this);
12941             store.on("remove", this.onRemove, this);
12942             store.on("update", this.onUpdate, this);
12943             store.on("clear", this.refresh, this);
12944             store.on("beforeload", this.onBeforeLoad, this);
12945             store.on("load", this.onLoad, this);
12946             store.on("loadexception", this.onLoad, this);
12947         }
12948         
12949         if(store){
12950             this.refresh();
12951         }
12952     },
12953     /**
12954      * onbeforeLoad - masks the loading area.
12955      *
12956      */
12957     onBeforeLoad : function(store,opts)
12958     {
12959          //Roo.log('onBeforeLoad');   
12960         if (!opts.add) {
12961             this.el.update("");
12962         }
12963         this.el.mask(this.mask ? this.mask : "Loading" ); 
12964     },
12965     onLoad : function ()
12966     {
12967         this.el.unmask();
12968     },
12969     
12970
12971     /**
12972      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12973      * @param {HTMLElement} node
12974      * @return {HTMLElement} The template node
12975      */
12976     findItemFromChild : function(node){
12977         var el = this.dataName  ?
12978             this.el.child('.roo-tpl-' + this.dataName,true) :
12979             this.el.dom; 
12980         
12981         if(!node || node.parentNode == el){
12982                     return node;
12983             }
12984             var p = node.parentNode;
12985             while(p && p != el){
12986             if(p.parentNode == el){
12987                 return p;
12988             }
12989             p = p.parentNode;
12990         }
12991             return null;
12992     },
12993
12994     /** @ignore */
12995     onClick : function(e){
12996         var item = this.findItemFromChild(e.getTarget());
12997         if(item){
12998             var index = this.indexOf(item);
12999             if(this.onItemClick(item, index, e) !== false){
13000                 this.fireEvent("click", this, index, item, e);
13001             }
13002         }else{
13003             this.clearSelections();
13004         }
13005     },
13006
13007     /** @ignore */
13008     onContextMenu : function(e){
13009         var item = this.findItemFromChild(e.getTarget());
13010         if(item){
13011             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13012         }
13013     },
13014
13015     /** @ignore */
13016     onDblClick : function(e){
13017         var item = this.findItemFromChild(e.getTarget());
13018         if(item){
13019             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13020         }
13021     },
13022
13023     onItemClick : function(item, index, e)
13024     {
13025         if(this.fireEvent("beforeclick", this, index, item, e) === false){
13026             return false;
13027         }
13028         if (this.toggleSelect) {
13029             var m = this.isSelected(item) ? 'unselect' : 'select';
13030             //Roo.log(m);
13031             var _t = this;
13032             _t[m](item, true, false);
13033             return true;
13034         }
13035         if(this.multiSelect || this.singleSelect){
13036             if(this.multiSelect && e.shiftKey && this.lastSelection){
13037                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13038             }else{
13039                 this.select(item, this.multiSelect && e.ctrlKey);
13040                 this.lastSelection = item;
13041             }
13042             
13043             if(!this.tickable){
13044                 e.preventDefault();
13045             }
13046             
13047         }
13048         return true;
13049     },
13050
13051     /**
13052      * Get the number of selected nodes.
13053      * @return {Number}
13054      */
13055     getSelectionCount : function(){
13056         return this.selections.length;
13057     },
13058
13059     /**
13060      * Get the currently selected nodes.
13061      * @return {Array} An array of HTMLElements
13062      */
13063     getSelectedNodes : function(){
13064         return this.selections;
13065     },
13066
13067     /**
13068      * Get the indexes of the selected nodes.
13069      * @return {Array}
13070      */
13071     getSelectedIndexes : function(){
13072         var indexes = [], s = this.selections;
13073         for(var i = 0, len = s.length; i < len; i++){
13074             indexes.push(s[i].nodeIndex);
13075         }
13076         return indexes;
13077     },
13078
13079     /**
13080      * Clear all selections
13081      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13082      */
13083     clearSelections : function(suppressEvent){
13084         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13085             this.cmp.elements = this.selections;
13086             this.cmp.removeClass(this.selectedClass);
13087             this.selections = [];
13088             if(!suppressEvent){
13089                 this.fireEvent("selectionchange", this, this.selections);
13090             }
13091         }
13092     },
13093
13094     /**
13095      * Returns true if the passed node is selected
13096      * @param {HTMLElement/Number} node The node or node index
13097      * @return {Boolean}
13098      */
13099     isSelected : function(node){
13100         var s = this.selections;
13101         if(s.length < 1){
13102             return false;
13103         }
13104         node = this.getNode(node);
13105         return s.indexOf(node) !== -1;
13106     },
13107
13108     /**
13109      * Selects nodes.
13110      * @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
13111      * @param {Boolean} keepExisting (optional) true to keep existing selections
13112      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13113      */
13114     select : function(nodeInfo, keepExisting, suppressEvent){
13115         if(nodeInfo instanceof Array){
13116             if(!keepExisting){
13117                 this.clearSelections(true);
13118             }
13119             for(var i = 0, len = nodeInfo.length; i < len; i++){
13120                 this.select(nodeInfo[i], true, true);
13121             }
13122             return;
13123         } 
13124         var node = this.getNode(nodeInfo);
13125         if(!node || this.isSelected(node)){
13126             return; // already selected.
13127         }
13128         if(!keepExisting){
13129             this.clearSelections(true);
13130         }
13131         
13132         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13133             Roo.fly(node).addClass(this.selectedClass);
13134             this.selections.push(node);
13135             if(!suppressEvent){
13136                 this.fireEvent("selectionchange", this, this.selections);
13137             }
13138         }
13139         
13140         
13141     },
13142       /**
13143      * Unselects nodes.
13144      * @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
13145      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13146      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13147      */
13148     unselect : function(nodeInfo, keepExisting, suppressEvent)
13149     {
13150         if(nodeInfo instanceof Array){
13151             Roo.each(this.selections, function(s) {
13152                 this.unselect(s, nodeInfo);
13153             }, this);
13154             return;
13155         }
13156         var node = this.getNode(nodeInfo);
13157         if(!node || !this.isSelected(node)){
13158             //Roo.log("not selected");
13159             return; // not selected.
13160         }
13161         // fireevent???
13162         var ns = [];
13163         Roo.each(this.selections, function(s) {
13164             if (s == node ) {
13165                 Roo.fly(node).removeClass(this.selectedClass);
13166
13167                 return;
13168             }
13169             ns.push(s);
13170         },this);
13171         
13172         this.selections= ns;
13173         this.fireEvent("selectionchange", this, this.selections);
13174     },
13175
13176     /**
13177      * Gets a template node.
13178      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13179      * @return {HTMLElement} The node or null if it wasn't found
13180      */
13181     getNode : function(nodeInfo){
13182         if(typeof nodeInfo == "string"){
13183             return document.getElementById(nodeInfo);
13184         }else if(typeof nodeInfo == "number"){
13185             return this.nodes[nodeInfo];
13186         }
13187         return nodeInfo;
13188     },
13189
13190     /**
13191      * Gets a range template nodes.
13192      * @param {Number} startIndex
13193      * @param {Number} endIndex
13194      * @return {Array} An array of nodes
13195      */
13196     getNodes : function(start, end){
13197         var ns = this.nodes;
13198         start = start || 0;
13199         end = typeof end == "undefined" ? ns.length - 1 : end;
13200         var nodes = [];
13201         if(start <= end){
13202             for(var i = start; i <= end; i++){
13203                 nodes.push(ns[i]);
13204             }
13205         } else{
13206             for(var i = start; i >= end; i--){
13207                 nodes.push(ns[i]);
13208             }
13209         }
13210         return nodes;
13211     },
13212
13213     /**
13214      * Finds the index of the passed node
13215      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13216      * @return {Number} The index of the node or -1
13217      */
13218     indexOf : function(node){
13219         node = this.getNode(node);
13220         if(typeof node.nodeIndex == "number"){
13221             return node.nodeIndex;
13222         }
13223         var ns = this.nodes;
13224         for(var i = 0, len = ns.length; i < len; i++){
13225             if(ns[i] == node){
13226                 return i;
13227             }
13228         }
13229         return -1;
13230     }
13231 });
13232 /*
13233  * - LGPL
13234  *
13235  * based on jquery fullcalendar
13236  * 
13237  */
13238
13239 Roo.bootstrap = Roo.bootstrap || {};
13240 /**
13241  * @class Roo.bootstrap.Calendar
13242  * @extends Roo.bootstrap.Component
13243  * Bootstrap Calendar class
13244  * @cfg {Boolean} loadMask (true|false) default false
13245  * @cfg {Object} header generate the user specific header of the calendar, default false
13246
13247  * @constructor
13248  * Create a new Container
13249  * @param {Object} config The config object
13250  */
13251
13252
13253
13254 Roo.bootstrap.Calendar = function(config){
13255     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13256      this.addEvents({
13257         /**
13258              * @event select
13259              * Fires when a date is selected
13260              * @param {DatePicker} this
13261              * @param {Date} date The selected date
13262              */
13263         'select': true,
13264         /**
13265              * @event monthchange
13266              * Fires when the displayed month changes 
13267              * @param {DatePicker} this
13268              * @param {Date} date The selected month
13269              */
13270         'monthchange': true,
13271         /**
13272              * @event evententer
13273              * Fires when mouse over an event
13274              * @param {Calendar} this
13275              * @param {event} Event
13276              */
13277         'evententer': true,
13278         /**
13279              * @event eventleave
13280              * Fires when the mouse leaves an
13281              * @param {Calendar} this
13282              * @param {event}
13283              */
13284         'eventleave': true,
13285         /**
13286              * @event eventclick
13287              * Fires when the mouse click an
13288              * @param {Calendar} this
13289              * @param {event}
13290              */
13291         'eventclick': true
13292         
13293     });
13294
13295 };
13296
13297 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
13298     
13299      /**
13300      * @cfg {Number} startDay
13301      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13302      */
13303     startDay : 0,
13304     
13305     loadMask : false,
13306     
13307     header : false,
13308       
13309     getAutoCreate : function(){
13310         
13311         
13312         var fc_button = function(name, corner, style, content ) {
13313             return Roo.apply({},{
13314                 tag : 'span',
13315                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
13316                          (corner.length ?
13317                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13318                             ''
13319                         ),
13320                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13321                 unselectable: 'on'
13322             });
13323         };
13324         
13325         var header = {};
13326         
13327         if(!this.header){
13328             header = {
13329                 tag : 'table',
13330                 cls : 'fc-header',
13331                 style : 'width:100%',
13332                 cn : [
13333                     {
13334                         tag: 'tr',
13335                         cn : [
13336                             {
13337                                 tag : 'td',
13338                                 cls : 'fc-header-left',
13339                                 cn : [
13340                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
13341                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
13342                                     { tag: 'span', cls: 'fc-header-space' },
13343                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
13344
13345
13346                                 ]
13347                             },
13348
13349                             {
13350                                 tag : 'td',
13351                                 cls : 'fc-header-center',
13352                                 cn : [
13353                                     {
13354                                         tag: 'span',
13355                                         cls: 'fc-header-title',
13356                                         cn : {
13357                                             tag: 'H2',
13358                                             html : 'month / year'
13359                                         }
13360                                     }
13361
13362                                 ]
13363                             },
13364                             {
13365                                 tag : 'td',
13366                                 cls : 'fc-header-right',
13367                                 cn : [
13368                               /*      fc_button('month', 'left', '', 'month' ),
13369                                     fc_button('week', '', '', 'week' ),
13370                                     fc_button('day', 'right', '', 'day' )
13371                                 */    
13372
13373                                 ]
13374                             }
13375
13376                         ]
13377                     }
13378                 ]
13379             };
13380         }
13381         
13382         header = this.header;
13383         
13384        
13385         var cal_heads = function() {
13386             var ret = [];
13387             // fixme - handle this.
13388             
13389             for (var i =0; i < Date.dayNames.length; i++) {
13390                 var d = Date.dayNames[i];
13391                 ret.push({
13392                     tag: 'th',
13393                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13394                     html : d.substring(0,3)
13395                 });
13396                 
13397             }
13398             ret[0].cls += ' fc-first';
13399             ret[6].cls += ' fc-last';
13400             return ret;
13401         };
13402         var cal_cell = function(n) {
13403             return  {
13404                 tag: 'td',
13405                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13406                 cn : [
13407                     {
13408                         cn : [
13409                             {
13410                                 cls: 'fc-day-number',
13411                                 html: 'D'
13412                             },
13413                             {
13414                                 cls: 'fc-day-content',
13415                              
13416                                 cn : [
13417                                      {
13418                                         style: 'position: relative;' // height: 17px;
13419                                     }
13420                                 ]
13421                             }
13422                             
13423                             
13424                         ]
13425                     }
13426                 ]
13427                 
13428             }
13429         };
13430         var cal_rows = function() {
13431             
13432             var ret = [];
13433             for (var r = 0; r < 6; r++) {
13434                 var row= {
13435                     tag : 'tr',
13436                     cls : 'fc-week',
13437                     cn : []
13438                 };
13439                 
13440                 for (var i =0; i < Date.dayNames.length; i++) {
13441                     var d = Date.dayNames[i];
13442                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13443
13444                 }
13445                 row.cn[0].cls+=' fc-first';
13446                 row.cn[0].cn[0].style = 'min-height:90px';
13447                 row.cn[6].cls+=' fc-last';
13448                 ret.push(row);
13449                 
13450             }
13451             ret[0].cls += ' fc-first';
13452             ret[4].cls += ' fc-prev-last';
13453             ret[5].cls += ' fc-last';
13454             return ret;
13455             
13456         };
13457         
13458         var cal_table = {
13459             tag: 'table',
13460             cls: 'fc-border-separate',
13461             style : 'width:100%',
13462             cellspacing  : 0,
13463             cn : [
13464                 { 
13465                     tag: 'thead',
13466                     cn : [
13467                         { 
13468                             tag: 'tr',
13469                             cls : 'fc-first fc-last',
13470                             cn : cal_heads()
13471                         }
13472                     ]
13473                 },
13474                 { 
13475                     tag: 'tbody',
13476                     cn : cal_rows()
13477                 }
13478                   
13479             ]
13480         };
13481          
13482          var cfg = {
13483             cls : 'fc fc-ltr',
13484             cn : [
13485                 header,
13486                 {
13487                     cls : 'fc-content',
13488                     style : "position: relative;",
13489                     cn : [
13490                         {
13491                             cls : 'fc-view fc-view-month fc-grid',
13492                             style : 'position: relative',
13493                             unselectable : 'on',
13494                             cn : [
13495                                 {
13496                                     cls : 'fc-event-container',
13497                                     style : 'position:absolute;z-index:8;top:0;left:0;'
13498                                 },
13499                                 cal_table
13500                             ]
13501                         }
13502                     ]
13503     
13504                 }
13505            ] 
13506             
13507         };
13508         
13509          
13510         
13511         return cfg;
13512     },
13513     
13514     
13515     initEvents : function()
13516     {
13517         if(!this.store){
13518             throw "can not find store for calendar";
13519         }
13520         
13521         var mark = {
13522             tag: "div",
13523             cls:"x-dlg-mask",
13524             style: "text-align:center",
13525             cn: [
13526                 {
13527                     tag: "div",
13528                     style: "background-color:white;width:50%;margin:250 auto",
13529                     cn: [
13530                         {
13531                             tag: "img",
13532                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
13533                         },
13534                         {
13535                             tag: "span",
13536                             html: "Loading"
13537                         }
13538                         
13539                     ]
13540                 }
13541             ]
13542         }
13543         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13544         
13545         var size = this.el.select('.fc-content', true).first().getSize();
13546         this.maskEl.setSize(size.width, size.height);
13547         this.maskEl.enableDisplayMode("block");
13548         if(!this.loadMask){
13549             this.maskEl.hide();
13550         }
13551         
13552         this.store = Roo.factory(this.store, Roo.data);
13553         this.store.on('load', this.onLoad, this);
13554         this.store.on('beforeload', this.onBeforeLoad, this);
13555         
13556         this.resize();
13557         
13558         this.cells = this.el.select('.fc-day',true);
13559         //Roo.log(this.cells);
13560         this.textNodes = this.el.query('.fc-day-number');
13561         this.cells.addClassOnOver('fc-state-hover');
13562         
13563         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13564         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13565         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13566         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13567         
13568         this.on('monthchange', this.onMonthChange, this);
13569         
13570         this.update(new Date().clearTime());
13571     },
13572     
13573     resize : function() {
13574         var sz  = this.el.getSize();
13575         
13576         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13577         this.el.select('.fc-day-content div',true).setHeight(34);
13578     },
13579     
13580     
13581     // private
13582     showPrevMonth : function(e){
13583         this.update(this.activeDate.add("mo", -1));
13584     },
13585     showToday : function(e){
13586         this.update(new Date().clearTime());
13587     },
13588     // private
13589     showNextMonth : function(e){
13590         this.update(this.activeDate.add("mo", 1));
13591     },
13592
13593     // private
13594     showPrevYear : function(){
13595         this.update(this.activeDate.add("y", -1));
13596     },
13597
13598     // private
13599     showNextYear : function(){
13600         this.update(this.activeDate.add("y", 1));
13601     },
13602
13603     
13604    // private
13605     update : function(date)
13606     {
13607         var vd = this.activeDate;
13608         this.activeDate = date;
13609 //        if(vd && this.el){
13610 //            var t = date.getTime();
13611 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13612 //                Roo.log('using add remove');
13613 //                
13614 //                this.fireEvent('monthchange', this, date);
13615 //                
13616 //                this.cells.removeClass("fc-state-highlight");
13617 //                this.cells.each(function(c){
13618 //                   if(c.dateValue == t){
13619 //                       c.addClass("fc-state-highlight");
13620 //                       setTimeout(function(){
13621 //                            try{c.dom.firstChild.focus();}catch(e){}
13622 //                       }, 50);
13623 //                       return false;
13624 //                   }
13625 //                   return true;
13626 //                });
13627 //                return;
13628 //            }
13629 //        }
13630         
13631         var days = date.getDaysInMonth();
13632         
13633         var firstOfMonth = date.getFirstDateOfMonth();
13634         var startingPos = firstOfMonth.getDay()-this.startDay;
13635         
13636         if(startingPos < this.startDay){
13637             startingPos += 7;
13638         }
13639         
13640         var pm = date.add(Date.MONTH, -1);
13641         var prevStart = pm.getDaysInMonth()-startingPos;
13642 //        
13643         this.cells = this.el.select('.fc-day',true);
13644         this.textNodes = this.el.query('.fc-day-number');
13645         this.cells.addClassOnOver('fc-state-hover');
13646         
13647         var cells = this.cells.elements;
13648         var textEls = this.textNodes;
13649         
13650         Roo.each(cells, function(cell){
13651             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13652         });
13653         
13654         days += startingPos;
13655
13656         // convert everything to numbers so it's fast
13657         var day = 86400000;
13658         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13659         //Roo.log(d);
13660         //Roo.log(pm);
13661         //Roo.log(prevStart);
13662         
13663         var today = new Date().clearTime().getTime();
13664         var sel = date.clearTime().getTime();
13665         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13666         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13667         var ddMatch = this.disabledDatesRE;
13668         var ddText = this.disabledDatesText;
13669         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13670         var ddaysText = this.disabledDaysText;
13671         var format = this.format;
13672         
13673         var setCellClass = function(cal, cell){
13674             cell.row = 0;
13675             cell.events = [];
13676             cell.more = [];
13677             //Roo.log('set Cell Class');
13678             cell.title = "";
13679             var t = d.getTime();
13680             
13681             //Roo.log(d);
13682             
13683             cell.dateValue = t;
13684             if(t == today){
13685                 cell.className += " fc-today";
13686                 cell.className += " fc-state-highlight";
13687                 cell.title = cal.todayText;
13688             }
13689             if(t == sel){
13690                 // disable highlight in other month..
13691                 //cell.className += " fc-state-highlight";
13692                 
13693             }
13694             // disabling
13695             if(t < min) {
13696                 cell.className = " fc-state-disabled";
13697                 cell.title = cal.minText;
13698                 return;
13699             }
13700             if(t > max) {
13701                 cell.className = " fc-state-disabled";
13702                 cell.title = cal.maxText;
13703                 return;
13704             }
13705             if(ddays){
13706                 if(ddays.indexOf(d.getDay()) != -1){
13707                     cell.title = ddaysText;
13708                     cell.className = " fc-state-disabled";
13709                 }
13710             }
13711             if(ddMatch && format){
13712                 var fvalue = d.dateFormat(format);
13713                 if(ddMatch.test(fvalue)){
13714                     cell.title = ddText.replace("%0", fvalue);
13715                     cell.className = " fc-state-disabled";
13716                 }
13717             }
13718             
13719             if (!cell.initialClassName) {
13720                 cell.initialClassName = cell.dom.className;
13721             }
13722             
13723             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
13724         };
13725
13726         var i = 0;
13727         
13728         for(; i < startingPos; i++) {
13729             textEls[i].innerHTML = (++prevStart);
13730             d.setDate(d.getDate()+1);
13731             
13732             cells[i].className = "fc-past fc-other-month";
13733             setCellClass(this, cells[i]);
13734         }
13735         
13736         var intDay = 0;
13737         
13738         for(; i < days; i++){
13739             intDay = i - startingPos + 1;
13740             textEls[i].innerHTML = (intDay);
13741             d.setDate(d.getDate()+1);
13742             
13743             cells[i].className = ''; // "x-date-active";
13744             setCellClass(this, cells[i]);
13745         }
13746         var extraDays = 0;
13747         
13748         for(; i < 42; i++) {
13749             textEls[i].innerHTML = (++extraDays);
13750             d.setDate(d.getDate()+1);
13751             
13752             cells[i].className = "fc-future fc-other-month";
13753             setCellClass(this, cells[i]);
13754         }
13755         
13756         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13757         
13758         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13759         
13760         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13761         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13762         
13763         if(totalRows != 6){
13764             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13765             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13766         }
13767         
13768         this.fireEvent('monthchange', this, date);
13769         
13770         
13771         /*
13772         if(!this.internalRender){
13773             var main = this.el.dom.firstChild;
13774             var w = main.offsetWidth;
13775             this.el.setWidth(w + this.el.getBorderWidth("lr"));
13776             Roo.fly(main).setWidth(w);
13777             this.internalRender = true;
13778             // opera does not respect the auto grow header center column
13779             // then, after it gets a width opera refuses to recalculate
13780             // without a second pass
13781             if(Roo.isOpera && !this.secondPass){
13782                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13783                 this.secondPass = true;
13784                 this.update.defer(10, this, [date]);
13785             }
13786         }
13787         */
13788         
13789     },
13790     
13791     findCell : function(dt) {
13792         dt = dt.clearTime().getTime();
13793         var ret = false;
13794         this.cells.each(function(c){
13795             //Roo.log("check " +c.dateValue + '?=' + dt);
13796             if(c.dateValue == dt){
13797                 ret = c;
13798                 return false;
13799             }
13800             return true;
13801         });
13802         
13803         return ret;
13804     },
13805     
13806     findCells : function(ev) {
13807         var s = ev.start.clone().clearTime().getTime();
13808        // Roo.log(s);
13809         var e= ev.end.clone().clearTime().getTime();
13810        // Roo.log(e);
13811         var ret = [];
13812         this.cells.each(function(c){
13813              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13814             
13815             if(c.dateValue > e){
13816                 return ;
13817             }
13818             if(c.dateValue < s){
13819                 return ;
13820             }
13821             ret.push(c);
13822         });
13823         
13824         return ret;    
13825     },
13826     
13827 //    findBestRow: function(cells)
13828 //    {
13829 //        var ret = 0;
13830 //        
13831 //        for (var i =0 ; i < cells.length;i++) {
13832 //            ret  = Math.max(cells[i].rows || 0,ret);
13833 //        }
13834 //        return ret;
13835 //        
13836 //    },
13837     
13838     
13839     addItem : function(ev)
13840     {
13841         // look for vertical location slot in
13842         var cells = this.findCells(ev);
13843         
13844 //        ev.row = this.findBestRow(cells);
13845         
13846         // work out the location.
13847         
13848         var crow = false;
13849         var rows = [];
13850         for(var i =0; i < cells.length; i++) {
13851             
13852             cells[i].row = cells[0].row;
13853             
13854             if(i == 0){
13855                 cells[i].row = cells[i].row + 1;
13856             }
13857             
13858             if (!crow) {
13859                 crow = {
13860                     start : cells[i],
13861                     end :  cells[i]
13862                 };
13863                 continue;
13864             }
13865             if (crow.start.getY() == cells[i].getY()) {
13866                 // on same row.
13867                 crow.end = cells[i];
13868                 continue;
13869             }
13870             // different row.
13871             rows.push(crow);
13872             crow = {
13873                 start: cells[i],
13874                 end : cells[i]
13875             };
13876             
13877         }
13878         
13879         rows.push(crow);
13880         ev.els = [];
13881         ev.rows = rows;
13882         ev.cells = cells;
13883         
13884         cells[0].events.push(ev);
13885         
13886         this.calevents.push(ev);
13887     },
13888     
13889     clearEvents: function() {
13890         
13891         if(!this.calevents){
13892             return;
13893         }
13894         
13895         Roo.each(this.cells.elements, function(c){
13896             c.row = 0;
13897             c.events = [];
13898             c.more = [];
13899         });
13900         
13901         Roo.each(this.calevents, function(e) {
13902             Roo.each(e.els, function(el) {
13903                 el.un('mouseenter' ,this.onEventEnter, this);
13904                 el.un('mouseleave' ,this.onEventLeave, this);
13905                 el.remove();
13906             },this);
13907         },this);
13908         
13909         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13910             e.remove();
13911         });
13912         
13913     },
13914     
13915     renderEvents: function()
13916     {   
13917         var _this = this;
13918         
13919         this.cells.each(function(c) {
13920             
13921             if(c.row < 5){
13922                 return;
13923             }
13924             
13925             var ev = c.events;
13926             
13927             var r = 4;
13928             if(c.row != c.events.length){
13929                 r = 4 - (4 - (c.row - c.events.length));
13930             }
13931             
13932             c.events = ev.slice(0, r);
13933             c.more = ev.slice(r);
13934             
13935             if(c.more.length && c.more.length == 1){
13936                 c.events.push(c.more.pop());
13937             }
13938             
13939             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13940             
13941         });
13942             
13943         this.cells.each(function(c) {
13944             
13945             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13946             
13947             
13948             for (var e = 0; e < c.events.length; e++){
13949                 var ev = c.events[e];
13950                 var rows = ev.rows;
13951                 
13952                 for(var i = 0; i < rows.length; i++) {
13953                 
13954                     // how many rows should it span..
13955
13956                     var  cfg = {
13957                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13958                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13959
13960                         unselectable : "on",
13961                         cn : [
13962                             {
13963                                 cls: 'fc-event-inner',
13964                                 cn : [
13965     //                                {
13966     //                                  tag:'span',
13967     //                                  cls: 'fc-event-time',
13968     //                                  html : cells.length > 1 ? '' : ev.time
13969     //                                },
13970                                     {
13971                                       tag:'span',
13972                                       cls: 'fc-event-title',
13973                                       html : String.format('{0}', ev.title)
13974                                     }
13975
13976
13977                                 ]
13978                             },
13979                             {
13980                                 cls: 'ui-resizable-handle ui-resizable-e',
13981                                 html : '&nbsp;&nbsp;&nbsp'
13982                             }
13983
13984                         ]
13985                     };
13986
13987                     if (i == 0) {
13988                         cfg.cls += ' fc-event-start';
13989                     }
13990                     if ((i+1) == rows.length) {
13991                         cfg.cls += ' fc-event-end';
13992                     }
13993
13994                     var ctr = _this.el.select('.fc-event-container',true).first();
13995                     var cg = ctr.createChild(cfg);
13996
13997                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
13998                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
13999
14000                     var r = (c.more.length) ? 1 : 0;
14001                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
14002                     cg.setWidth(ebox.right - sbox.x -2);
14003
14004                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14005                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14006                     cg.on('click', _this.onEventClick, _this, ev);
14007
14008                     ev.els.push(cg);
14009                     
14010                 }
14011                 
14012             }
14013             
14014             
14015             if(c.more.length){
14016                 var  cfg = {
14017                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14018                     style : 'position: absolute',
14019                     unselectable : "on",
14020                     cn : [
14021                         {
14022                             cls: 'fc-event-inner',
14023                             cn : [
14024                                 {
14025                                   tag:'span',
14026                                   cls: 'fc-event-title',
14027                                   html : 'More'
14028                                 }
14029
14030
14031                             ]
14032                         },
14033                         {
14034                             cls: 'ui-resizable-handle ui-resizable-e',
14035                             html : '&nbsp;&nbsp;&nbsp'
14036                         }
14037
14038                     ]
14039                 };
14040
14041                 var ctr = _this.el.select('.fc-event-container',true).first();
14042                 var cg = ctr.createChild(cfg);
14043
14044                 var sbox = c.select('.fc-day-content',true).first().getBox();
14045                 var ebox = c.select('.fc-day-content',true).first().getBox();
14046                 //Roo.log(cg);
14047                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
14048                 cg.setWidth(ebox.right - sbox.x -2);
14049
14050                 cg.on('click', _this.onMoreEventClick, _this, c.more);
14051                 
14052             }
14053             
14054         });
14055         
14056         
14057         
14058     },
14059     
14060     onEventEnter: function (e, el,event,d) {
14061         this.fireEvent('evententer', this, el, event);
14062     },
14063     
14064     onEventLeave: function (e, el,event,d) {
14065         this.fireEvent('eventleave', this, el, event);
14066     },
14067     
14068     onEventClick: function (e, el,event,d) {
14069         this.fireEvent('eventclick', this, el, event);
14070     },
14071     
14072     onMonthChange: function () {
14073         this.store.load();
14074     },
14075     
14076     onMoreEventClick: function(e, el, more)
14077     {
14078         var _this = this;
14079         
14080         this.calpopover.placement = 'right';
14081         this.calpopover.setTitle('More');
14082         
14083         this.calpopover.setContent('');
14084         
14085         var ctr = this.calpopover.el.select('.popover-content', true).first();
14086         
14087         Roo.each(more, function(m){
14088             var cfg = {
14089                 cls : 'fc-event-hori fc-event-draggable',
14090                 html : m.title
14091             }
14092             var cg = ctr.createChild(cfg);
14093             
14094             cg.on('click', _this.onEventClick, _this, m);
14095         });
14096         
14097         this.calpopover.show(el);
14098         
14099         
14100     },
14101     
14102     onLoad: function () 
14103     {   
14104         this.calevents = [];
14105         var cal = this;
14106         
14107         if(this.store.getCount() > 0){
14108             this.store.data.each(function(d){
14109                cal.addItem({
14110                     id : d.data.id,
14111                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14112                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14113                     time : d.data.start_time,
14114                     title : d.data.title,
14115                     description : d.data.description,
14116                     venue : d.data.venue
14117                 });
14118             });
14119         }
14120         
14121         this.renderEvents();
14122         
14123         if(this.calevents.length && this.loadMask){
14124             this.maskEl.hide();
14125         }
14126     },
14127     
14128     onBeforeLoad: function()
14129     {
14130         this.clearEvents();
14131         if(this.loadMask){
14132             this.maskEl.show();
14133         }
14134     }
14135 });
14136
14137  
14138  /*
14139  * - LGPL
14140  *
14141  * element
14142  * 
14143  */
14144
14145 /**
14146  * @class Roo.bootstrap.Popover
14147  * @extends Roo.bootstrap.Component
14148  * Bootstrap Popover class
14149  * @cfg {String} html contents of the popover   (or false to use children..)
14150  * @cfg {String} title of popover (or false to hide)
14151  * @cfg {String} placement how it is placed
14152  * @cfg {String} trigger click || hover (or false to trigger manually)
14153  * @cfg {String} over what (parent or false to trigger manually.)
14154  * @cfg {Number} delay - delay before showing
14155  
14156  * @constructor
14157  * Create a new Popover
14158  * @param {Object} config The config object
14159  */
14160
14161 Roo.bootstrap.Popover = function(config){
14162     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14163 };
14164
14165 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
14166     
14167     title: 'Fill in a title',
14168     html: false,
14169     
14170     placement : 'right',
14171     trigger : 'hover', // hover
14172     
14173     delay : 0,
14174     
14175     over: 'parent',
14176     
14177     can_build_overlaid : false,
14178     
14179     getChildContainer : function()
14180     {
14181         return this.el.select('.popover-content',true).first();
14182     },
14183     
14184     getAutoCreate : function(){
14185          Roo.log('make popover?');
14186         var cfg = {
14187            cls : 'popover roo-dynamic',
14188            style: 'display:block',
14189            cn : [
14190                 {
14191                     cls : 'arrow'
14192                 },
14193                 {
14194                     cls : 'popover-inner',
14195                     cn : [
14196                         {
14197                             tag: 'h3',
14198                             cls: 'popover-title',
14199                             html : this.title
14200                         },
14201                         {
14202                             cls : 'popover-content',
14203                             html : this.html
14204                         }
14205                     ]
14206                     
14207                 }
14208            ]
14209         };
14210         
14211         return cfg;
14212     },
14213     setTitle: function(str)
14214     {
14215         this.el.select('.popover-title',true).first().dom.innerHTML = str;
14216     },
14217     setContent: function(str)
14218     {
14219         this.el.select('.popover-content',true).first().dom.innerHTML = str;
14220     },
14221     // as it get's added to the bottom of the page.
14222     onRender : function(ct, position)
14223     {
14224         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14225         if(!this.el){
14226             var cfg = Roo.apply({},  this.getAutoCreate());
14227             cfg.id = Roo.id();
14228             
14229             if (this.cls) {
14230                 cfg.cls += ' ' + this.cls;
14231             }
14232             if (this.style) {
14233                 cfg.style = this.style;
14234             }
14235             Roo.log("adding to ")
14236             this.el = Roo.get(document.body).createChild(cfg, position);
14237             Roo.log(this.el);
14238         }
14239         this.initEvents();
14240     },
14241     
14242     initEvents : function()
14243     {
14244         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14245         this.el.enableDisplayMode('block');
14246         this.el.hide();
14247         if (this.over === false) {
14248             return; 
14249         }
14250         if (this.triggers === false) {
14251             return;
14252         }
14253         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14254         var triggers = this.trigger ? this.trigger.split(' ') : [];
14255         Roo.each(triggers, function(trigger) {
14256         
14257             if (trigger == 'click') {
14258                 on_el.on('click', this.toggle, this);
14259             } else if (trigger != 'manual') {
14260                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
14261                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14262       
14263                 on_el.on(eventIn  ,this.enter, this);
14264                 on_el.on(eventOut, this.leave, this);
14265             }
14266         }, this);
14267         
14268     },
14269     
14270     
14271     // private
14272     timeout : null,
14273     hoverState : null,
14274     
14275     toggle : function () {
14276         this.hoverState == 'in' ? this.leave() : this.enter();
14277     },
14278     
14279     enter : function () {
14280        
14281     
14282         clearTimeout(this.timeout);
14283     
14284         this.hoverState = 'in';
14285     
14286         if (!this.delay || !this.delay.show) {
14287             this.show();
14288             return;
14289         }
14290         var _t = this;
14291         this.timeout = setTimeout(function () {
14292             if (_t.hoverState == 'in') {
14293                 _t.show();
14294             }
14295         }, this.delay.show)
14296     },
14297     leave : function() {
14298         clearTimeout(this.timeout);
14299     
14300         this.hoverState = 'out';
14301     
14302         if (!this.delay || !this.delay.hide) {
14303             this.hide();
14304             return;
14305         }
14306         var _t = this;
14307         this.timeout = setTimeout(function () {
14308             if (_t.hoverState == 'out') {
14309                 _t.hide();
14310             }
14311         }, this.delay.hide)
14312     },
14313     
14314     show : function (on_el)
14315     {
14316         if (!on_el) {
14317             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14318         }
14319         // set content.
14320         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14321         if (this.html !== false) {
14322             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14323         }
14324         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14325         if (!this.title.length) {
14326             this.el.select('.popover-title',true).hide();
14327         }
14328         
14329         var placement = typeof this.placement == 'function' ?
14330             this.placement.call(this, this.el, on_el) :
14331             this.placement;
14332             
14333         var autoToken = /\s?auto?\s?/i;
14334         var autoPlace = autoToken.test(placement);
14335         if (autoPlace) {
14336             placement = placement.replace(autoToken, '') || 'top';
14337         }
14338         
14339         //this.el.detach()
14340         //this.el.setXY([0,0]);
14341         this.el.show();
14342         this.el.dom.style.display='block';
14343         this.el.addClass(placement);
14344         
14345         //this.el.appendTo(on_el);
14346         
14347         var p = this.getPosition();
14348         var box = this.el.getBox();
14349         
14350         if (autoPlace) {
14351             // fixme..
14352         }
14353         var align = Roo.bootstrap.Popover.alignment[placement];
14354         this.el.alignTo(on_el, align[0],align[1]);
14355         //var arrow = this.el.select('.arrow',true).first();
14356         //arrow.set(align[2], 
14357         
14358         this.el.addClass('in');
14359         this.hoverState = null;
14360         
14361         if (this.el.hasClass('fade')) {
14362             // fade it?
14363         }
14364         
14365     },
14366     hide : function()
14367     {
14368         this.el.setXY([0,0]);
14369         this.el.removeClass('in');
14370         this.el.hide();
14371         
14372     }
14373     
14374 });
14375
14376 Roo.bootstrap.Popover.alignment = {
14377     'left' : ['r-l', [-10,0], 'right'],
14378     'right' : ['l-r', [10,0], 'left'],
14379     'bottom' : ['t-b', [0,10], 'top'],
14380     'top' : [ 'b-t', [0,-10], 'bottom']
14381 };
14382
14383  /*
14384  * - LGPL
14385  *
14386  * Progress
14387  * 
14388  */
14389
14390 /**
14391  * @class Roo.bootstrap.Progress
14392  * @extends Roo.bootstrap.Component
14393  * Bootstrap Progress class
14394  * @cfg {Boolean} striped striped of the progress bar
14395  * @cfg {Boolean} active animated of the progress bar
14396  * 
14397  * 
14398  * @constructor
14399  * Create a new Progress
14400  * @param {Object} config The config object
14401  */
14402
14403 Roo.bootstrap.Progress = function(config){
14404     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14405 };
14406
14407 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
14408     
14409     striped : false,
14410     active: false,
14411     
14412     getAutoCreate : function(){
14413         var cfg = {
14414             tag: 'div',
14415             cls: 'progress'
14416         };
14417         
14418         
14419         if(this.striped){
14420             cfg.cls += ' progress-striped';
14421         }
14422       
14423         if(this.active){
14424             cfg.cls += ' active';
14425         }
14426         
14427         
14428         return cfg;
14429     }
14430    
14431 });
14432
14433  
14434
14435  /*
14436  * - LGPL
14437  *
14438  * ProgressBar
14439  * 
14440  */
14441
14442 /**
14443  * @class Roo.bootstrap.ProgressBar
14444  * @extends Roo.bootstrap.Component
14445  * Bootstrap ProgressBar class
14446  * @cfg {Number} aria_valuenow aria-value now
14447  * @cfg {Number} aria_valuemin aria-value min
14448  * @cfg {Number} aria_valuemax aria-value max
14449  * @cfg {String} label label for the progress bar
14450  * @cfg {String} panel (success | info | warning | danger )
14451  * @cfg {String} role role of the progress bar
14452  * @cfg {String} sr_only text
14453  * 
14454  * 
14455  * @constructor
14456  * Create a new ProgressBar
14457  * @param {Object} config The config object
14458  */
14459
14460 Roo.bootstrap.ProgressBar = function(config){
14461     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14462 };
14463
14464 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
14465     
14466     aria_valuenow : 0,
14467     aria_valuemin : 0,
14468     aria_valuemax : 100,
14469     label : false,
14470     panel : false,
14471     role : false,
14472     sr_only: false,
14473     
14474     getAutoCreate : function()
14475     {
14476         
14477         var cfg = {
14478             tag: 'div',
14479             cls: 'progress-bar',
14480             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14481         };
14482         
14483         if(this.sr_only){
14484             cfg.cn = {
14485                 tag: 'span',
14486                 cls: 'sr-only',
14487                 html: this.sr_only
14488             }
14489         }
14490         
14491         if(this.role){
14492             cfg.role = this.role;
14493         }
14494         
14495         if(this.aria_valuenow){
14496             cfg['aria-valuenow'] = this.aria_valuenow;
14497         }
14498         
14499         if(this.aria_valuemin){
14500             cfg['aria-valuemin'] = this.aria_valuemin;
14501         }
14502         
14503         if(this.aria_valuemax){
14504             cfg['aria-valuemax'] = this.aria_valuemax;
14505         }
14506         
14507         if(this.label && !this.sr_only){
14508             cfg.html = this.label;
14509         }
14510         
14511         if(this.panel){
14512             cfg.cls += ' progress-bar-' + this.panel;
14513         }
14514         
14515         return cfg;
14516     },
14517     
14518     update : function(aria_valuenow)
14519     {
14520         this.aria_valuenow = aria_valuenow;
14521         
14522         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14523     }
14524    
14525 });
14526
14527  
14528
14529  /*
14530  * - LGPL
14531  *
14532  * column
14533  * 
14534  */
14535
14536 /**
14537  * @class Roo.bootstrap.TabGroup
14538  * @extends Roo.bootstrap.Column
14539  * Bootstrap Column class
14540  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14541  * @cfg {Boolean} carousel true to make the group behave like a carousel
14542  * 
14543  * @constructor
14544  * Create a new TabGroup
14545  * @param {Object} config The config object
14546  */
14547
14548 Roo.bootstrap.TabGroup = function(config){
14549     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14550     if (!this.navId) {
14551         this.navId = Roo.id();
14552     }
14553     this.tabs = [];
14554     Roo.bootstrap.TabGroup.register(this);
14555     
14556 };
14557
14558 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
14559     
14560     carousel : false,
14561     transition : false,
14562      
14563     getAutoCreate : function()
14564     {
14565         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14566         
14567         cfg.cls += ' tab-content';
14568         
14569         if (this.carousel) {
14570             cfg.cls += ' carousel slide';
14571             cfg.cn = [{
14572                cls : 'carousel-inner'
14573             }]
14574         }
14575         
14576         
14577         return cfg;
14578     },
14579     getChildContainer : function()
14580     {
14581         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14582     },
14583     
14584     /**
14585     * register a Navigation item
14586     * @param {Roo.bootstrap.NavItem} the navitem to add
14587     */
14588     register : function(item)
14589     {
14590         this.tabs.push( item);
14591         item.navId = this.navId; // not really needed..
14592     
14593     },
14594     
14595     getActivePanel : function()
14596     {
14597         var r = false;
14598         Roo.each(this.tabs, function(t) {
14599             if (t.active) {
14600                 r = t;
14601                 return false;
14602             }
14603             return null;
14604         });
14605         return r;
14606         
14607     },
14608     getPanelByName : function(n)
14609     {
14610         var r = false;
14611         Roo.each(this.tabs, function(t) {
14612             if (t.tabId == n) {
14613                 r = t;
14614                 return false;
14615             }
14616             return null;
14617         });
14618         return r;
14619     },
14620     indexOfPanel : function(p)
14621     {
14622         var r = false;
14623         Roo.each(this.tabs, function(t,i) {
14624             if (t.tabId == p.tabId) {
14625                 r = i;
14626                 return false;
14627             }
14628             return null;
14629         });
14630         return r;
14631     },
14632     /**
14633      * show a specific panel
14634      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14635      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14636      */
14637     showPanel : function (pan)
14638     {
14639         
14640         if (typeof(pan) == 'number') {
14641             pan = this.tabs[pan];
14642         }
14643         if (typeof(pan) == 'string') {
14644             pan = this.getPanelByName(pan);
14645         }
14646         if (pan.tabId == this.getActivePanel().tabId) {
14647             return true;
14648         }
14649         var cur = this.getActivePanel();
14650         
14651         if (false === cur.fireEvent('beforedeactivate')) {
14652             return false;
14653         }
14654         
14655         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14656             
14657             this.transition = true;
14658             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
14659             var lr = dir == 'next' ? 'left' : 'right';
14660             pan.el.addClass(dir); // or prev
14661             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14662             cur.el.addClass(lr); // or right
14663             pan.el.addClass(lr);
14664             
14665             var _this = this;
14666             cur.el.on('transitionend', function() {
14667                 Roo.log("trans end?");
14668                 
14669                 pan.el.removeClass([lr,dir]);
14670                 pan.setActive(true);
14671                 
14672                 cur.el.removeClass([lr]);
14673                 cur.setActive(false);
14674                 
14675                 _this.transition = false;
14676                 
14677             }, this, { single:  true } );
14678             return true;
14679         }
14680         
14681         cur.setActive(false);
14682         pan.setActive(true);
14683         return true;
14684         
14685     },
14686     showPanelNext : function()
14687     {
14688         var i = this.indexOfPanel(this.getActivePanel());
14689         if (i > this.tabs.length) {
14690             return;
14691         }
14692         this.showPanel(this.tabs[i+1]);
14693     },
14694     showPanelPrev : function()
14695     {
14696         var i = this.indexOfPanel(this.getActivePanel());
14697         if (i  < 1) {
14698             return;
14699         }
14700         this.showPanel(this.tabs[i-1]);
14701     }
14702     
14703     
14704   
14705 });
14706
14707  
14708
14709  
14710  
14711 Roo.apply(Roo.bootstrap.TabGroup, {
14712     
14713     groups: {},
14714      /**
14715     * register a Navigation Group
14716     * @param {Roo.bootstrap.NavGroup} the navgroup to add
14717     */
14718     register : function(navgrp)
14719     {
14720         this.groups[navgrp.navId] = navgrp;
14721         
14722     },
14723     /**
14724     * fetch a Navigation Group based on the navigation ID
14725     * if one does not exist , it will get created.
14726     * @param {string} the navgroup to add
14727     * @returns {Roo.bootstrap.NavGroup} the navgroup 
14728     */
14729     get: function(navId) {
14730         if (typeof(this.groups[navId]) == 'undefined') {
14731             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14732         }
14733         return this.groups[navId] ;
14734     }
14735     
14736     
14737     
14738 });
14739
14740  /*
14741  * - LGPL
14742  *
14743  * TabPanel
14744  * 
14745  */
14746
14747 /**
14748  * @class Roo.bootstrap.TabPanel
14749  * @extends Roo.bootstrap.Component
14750  * Bootstrap TabPanel class
14751  * @cfg {Boolean} active panel active
14752  * @cfg {String} html panel content
14753  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14754  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14755  * 
14756  * 
14757  * @constructor
14758  * Create a new TabPanel
14759  * @param {Object} config The config object
14760  */
14761
14762 Roo.bootstrap.TabPanel = function(config){
14763     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14764     this.addEvents({
14765         /**
14766              * @event changed
14767              * Fires when the active status changes
14768              * @param {Roo.bootstrap.TabPanel} this
14769              * @param {Boolean} state the new state
14770             
14771          */
14772         'changed': true,
14773         /**
14774              * @event beforedeactivate
14775              * Fires before a tab is de-activated - can be used to do validation on a form.
14776              * @param {Roo.bootstrap.TabPanel} this
14777              * @return {Boolean} false if there is an error
14778             
14779          */
14780         'beforedeactivate': true
14781      });
14782     
14783     this.tabId = this.tabId || Roo.id();
14784   
14785 };
14786
14787 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
14788     
14789     active: false,
14790     html: false,
14791     tabId: false,
14792     navId : false,
14793     
14794     getAutoCreate : function(){
14795         var cfg = {
14796             tag: 'div',
14797             // item is needed for carousel - not sure if it has any effect otherwise
14798             cls: 'tab-pane item',
14799             html: this.html || ''
14800         };
14801         
14802         if(this.active){
14803             cfg.cls += ' active';
14804         }
14805         
14806         if(this.tabId){
14807             cfg.tabId = this.tabId;
14808         }
14809         
14810         
14811         return cfg;
14812     },
14813     
14814     initEvents:  function()
14815     {
14816         Roo.log('-------- init events on tab panel ---------');
14817         
14818         var p = this.parent();
14819         this.navId = this.navId || p.navId;
14820         
14821         if (typeof(this.navId) != 'undefined') {
14822             // not really needed.. but just in case.. parent should be a NavGroup.
14823             var tg = Roo.bootstrap.TabGroup.get(this.navId);
14824             Roo.log(['register', tg, this]);
14825             tg.register(this);
14826         }
14827     },
14828     
14829     
14830     onRender : function(ct, position)
14831     {
14832        // Roo.log("Call onRender: " + this.xtype);
14833         
14834         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14835         
14836         
14837         
14838         
14839         
14840     },
14841     
14842     setActive: function(state)
14843     {
14844         Roo.log("panel - set active " + this.tabId + "=" + state);
14845         
14846         this.active = state;
14847         if (!state) {
14848             this.el.removeClass('active');
14849             
14850         } else  if (!this.el.hasClass('active')) {
14851             this.el.addClass('active');
14852         }
14853         this.fireEvent('changed', this, state);
14854     }
14855     
14856     
14857 });
14858  
14859
14860  
14861
14862  /*
14863  * - LGPL
14864  *
14865  * DateField
14866  * 
14867  */
14868
14869 /**
14870  * @class Roo.bootstrap.DateField
14871  * @extends Roo.bootstrap.Input
14872  * Bootstrap DateField class
14873  * @cfg {Number} weekStart default 0
14874  * @cfg {String} viewMode default empty, (months|years)
14875  * @cfg {String} minViewMode default empty, (months|years)
14876  * @cfg {Number} startDate default -Infinity
14877  * @cfg {Number} endDate default Infinity
14878  * @cfg {Boolean} todayHighlight default false
14879  * @cfg {Boolean} todayBtn default false
14880  * @cfg {Boolean} calendarWeeks default false
14881  * @cfg {Object} daysOfWeekDisabled default empty
14882  * @cfg {Boolean} singleMode default false (true | false)
14883  * 
14884  * @cfg {Boolean} keyboardNavigation default true
14885  * @cfg {String} language default en
14886  * 
14887  * @constructor
14888  * Create a new DateField
14889  * @param {Object} config The config object
14890  */
14891
14892 Roo.bootstrap.DateField = function(config){
14893     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14894      this.addEvents({
14895             /**
14896              * @event show
14897              * Fires when this field show.
14898              * @param {Roo.bootstrap.DateField} this
14899              * @param {Mixed} date The date value
14900              */
14901             show : true,
14902             /**
14903              * @event show
14904              * Fires when this field hide.
14905              * @param {Roo.bootstrap.DateField} this
14906              * @param {Mixed} date The date value
14907              */
14908             hide : true,
14909             /**
14910              * @event select
14911              * Fires when select a date.
14912              * @param {Roo.bootstrap.DateField} this
14913              * @param {Mixed} date The date value
14914              */
14915             select : true
14916         });
14917 };
14918
14919 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
14920     
14921     /**
14922      * @cfg {String} format
14923      * The default date format string which can be overriden for localization support.  The format must be
14924      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14925      */
14926     format : "m/d/y",
14927     /**
14928      * @cfg {String} altFormats
14929      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14930      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14931      */
14932     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14933     
14934     weekStart : 0,
14935     
14936     viewMode : '',
14937     
14938     minViewMode : '',
14939     
14940     todayHighlight : false,
14941     
14942     todayBtn: false,
14943     
14944     language: 'en',
14945     
14946     keyboardNavigation: true,
14947     
14948     calendarWeeks: false,
14949     
14950     startDate: -Infinity,
14951     
14952     endDate: Infinity,
14953     
14954     daysOfWeekDisabled: [],
14955     
14956     _events: [],
14957     
14958     singleMode : false,
14959     
14960     UTCDate: function()
14961     {
14962         return new Date(Date.UTC.apply(Date, arguments));
14963     },
14964     
14965     UTCToday: function()
14966     {
14967         var today = new Date();
14968         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14969     },
14970     
14971     getDate: function() {
14972             var d = this.getUTCDate();
14973             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14974     },
14975     
14976     getUTCDate: function() {
14977             return this.date;
14978     },
14979     
14980     setDate: function(d) {
14981             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14982     },
14983     
14984     setUTCDate: function(d) {
14985             this.date = d;
14986             this.setValue(this.formatDate(this.date));
14987     },
14988         
14989     onRender: function(ct, position)
14990     {
14991         
14992         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
14993         
14994         this.language = this.language || 'en';
14995         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
14996         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
14997         
14998         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
14999         this.format = this.format || 'm/d/y';
15000         this.isInline = false;
15001         this.isInput = true;
15002         this.component = this.el.select('.add-on', true).first() || false;
15003         this.component = (this.component && this.component.length === 0) ? false : this.component;
15004         this.hasInput = this.component && this.inputEL().length;
15005         
15006         if (typeof(this.minViewMode === 'string')) {
15007             switch (this.minViewMode) {
15008                 case 'months':
15009                     this.minViewMode = 1;
15010                     break;
15011                 case 'years':
15012                     this.minViewMode = 2;
15013                     break;
15014                 default:
15015                     this.minViewMode = 0;
15016                     break;
15017             }
15018         }
15019         
15020         if (typeof(this.viewMode === 'string')) {
15021             switch (this.viewMode) {
15022                 case 'months':
15023                     this.viewMode = 1;
15024                     break;
15025                 case 'years':
15026                     this.viewMode = 2;
15027                     break;
15028                 default:
15029                     this.viewMode = 0;
15030                     break;
15031             }
15032         }
15033                 
15034         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15035         
15036 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15037         
15038         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15039         
15040         this.picker().on('mousedown', this.onMousedown, this);
15041         this.picker().on('click', this.onClick, this);
15042         
15043         this.picker().addClass('datepicker-dropdown');
15044         
15045         this.startViewMode = this.viewMode;
15046         
15047         if(this.singleMode){
15048             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15049                 v.setVisibilityMode(Roo.Element.DISPLAY)
15050                 v.hide();
15051             });
15052             
15053             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15054                 v.setStyle('width', '189px');
15055             });
15056         }
15057         
15058         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15059             if(!this.calendarWeeks){
15060                 v.remove();
15061                 return;
15062             }
15063             
15064             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15065             v.attr('colspan', function(i, val){
15066                 return parseInt(val) + 1;
15067             });
15068         })
15069                         
15070         
15071         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15072         
15073         this.setStartDate(this.startDate);
15074         this.setEndDate(this.endDate);
15075         
15076         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15077         
15078         this.fillDow();
15079         this.fillMonths();
15080         this.update();
15081         this.showMode();
15082         
15083         if(this.isInline) {
15084             this.show();
15085         }
15086     },
15087     
15088     picker : function()
15089     {
15090         return this.pickerEl;
15091 //        return this.el.select('.datepicker', true).first();
15092     },
15093     
15094     fillDow: function()
15095     {
15096         var dowCnt = this.weekStart;
15097         
15098         var dow = {
15099             tag: 'tr',
15100             cn: [
15101                 
15102             ]
15103         };
15104         
15105         if(this.calendarWeeks){
15106             dow.cn.push({
15107                 tag: 'th',
15108                 cls: 'cw',
15109                 html: '&nbsp;'
15110             })
15111         }
15112         
15113         while (dowCnt < this.weekStart + 7) {
15114             dow.cn.push({
15115                 tag: 'th',
15116                 cls: 'dow',
15117                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15118             });
15119         }
15120         
15121         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15122     },
15123     
15124     fillMonths: function()
15125     {    
15126         var i = 0;
15127         var months = this.picker().select('>.datepicker-months td', true).first();
15128         
15129         months.dom.innerHTML = '';
15130         
15131         while (i < 12) {
15132             var month = {
15133                 tag: 'span',
15134                 cls: 'month',
15135                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15136             }
15137             
15138             months.createChild(month);
15139         }
15140         
15141     },
15142     
15143     update: function()
15144     {
15145         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;
15146         
15147         if (this.date < this.startDate) {
15148             this.viewDate = new Date(this.startDate);
15149         } else if (this.date > this.endDate) {
15150             this.viewDate = new Date(this.endDate);
15151         } else {
15152             this.viewDate = new Date(this.date);
15153         }
15154         
15155         this.fill();
15156     },
15157     
15158     fill: function() 
15159     {
15160         var d = new Date(this.viewDate),
15161                 year = d.getUTCFullYear(),
15162                 month = d.getUTCMonth(),
15163                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15164                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15165                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15166                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15167                 currentDate = this.date && this.date.valueOf(),
15168                 today = this.UTCToday();
15169         
15170         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15171         
15172 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15173         
15174 //        this.picker.select('>tfoot th.today').
15175 //                                              .text(dates[this.language].today)
15176 //                                              .toggle(this.todayBtn !== false);
15177     
15178         this.updateNavArrows();
15179         this.fillMonths();
15180                                                 
15181         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15182         
15183         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15184          
15185         prevMonth.setUTCDate(day);
15186         
15187         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15188         
15189         var nextMonth = new Date(prevMonth);
15190         
15191         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15192         
15193         nextMonth = nextMonth.valueOf();
15194         
15195         var fillMonths = false;
15196         
15197         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15198         
15199         while(prevMonth.valueOf() < nextMonth) {
15200             var clsName = '';
15201             
15202             if (prevMonth.getUTCDay() === this.weekStart) {
15203                 if(fillMonths){
15204                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15205                 }
15206                     
15207                 fillMonths = {
15208                     tag: 'tr',
15209                     cn: []
15210                 };
15211                 
15212                 if(this.calendarWeeks){
15213                     // ISO 8601: First week contains first thursday.
15214                     // ISO also states week starts on Monday, but we can be more abstract here.
15215                     var
15216                     // Start of current week: based on weekstart/current date
15217                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15218                     // Thursday of this week
15219                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15220                     // First Thursday of year, year from thursday
15221                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15222                     // Calendar week: ms between thursdays, div ms per day, div 7 days
15223                     calWeek =  (th - yth) / 864e5 / 7 + 1;
15224                     
15225                     fillMonths.cn.push({
15226                         tag: 'td',
15227                         cls: 'cw',
15228                         html: calWeek
15229                     });
15230                 }
15231             }
15232             
15233             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15234                 clsName += ' old';
15235             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15236                 clsName += ' new';
15237             }
15238             if (this.todayHighlight &&
15239                 prevMonth.getUTCFullYear() == today.getFullYear() &&
15240                 prevMonth.getUTCMonth() == today.getMonth() &&
15241                 prevMonth.getUTCDate() == today.getDate()) {
15242                 clsName += ' today';
15243             }
15244             
15245             if (currentDate && prevMonth.valueOf() === currentDate) {
15246                 clsName += ' active';
15247             }
15248             
15249             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15250                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15251                     clsName += ' disabled';
15252             }
15253             
15254             fillMonths.cn.push({
15255                 tag: 'td',
15256                 cls: 'day ' + clsName,
15257                 html: prevMonth.getDate()
15258             })
15259             
15260             prevMonth.setDate(prevMonth.getDate()+1);
15261         }
15262           
15263         var currentYear = this.date && this.date.getUTCFullYear();
15264         var currentMonth = this.date && this.date.getUTCMonth();
15265         
15266         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15267         
15268         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15269             v.removeClass('active');
15270             
15271             if(currentYear === year && k === currentMonth){
15272                 v.addClass('active');
15273             }
15274             
15275             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15276                 v.addClass('disabled');
15277             }
15278             
15279         });
15280         
15281         
15282         year = parseInt(year/10, 10) * 10;
15283         
15284         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15285         
15286         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15287         
15288         year -= 1;
15289         for (var i = -1; i < 11; i++) {
15290             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15291                 tag: 'span',
15292                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15293                 html: year
15294             })
15295             
15296             year += 1;
15297         }
15298     },
15299     
15300     showMode: function(dir) 
15301     {
15302         if (dir) {
15303             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15304         }
15305         
15306         Roo.each(this.picker().select('>div',true).elements, function(v){
15307             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15308             v.hide();
15309         });
15310         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15311     },
15312     
15313     place: function()
15314     {
15315         if(this.isInline) return;
15316         
15317         this.picker().removeClass(['bottom', 'top']);
15318         
15319         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15320             /*
15321              * place to the top of element!
15322              *
15323              */
15324             
15325             this.picker().addClass('top');
15326             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15327             
15328             return;
15329         }
15330         
15331         this.picker().addClass('bottom');
15332         
15333         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15334     },
15335     
15336     parseDate : function(value)
15337     {
15338         if(!value || value instanceof Date){
15339             return value;
15340         }
15341         var v = Date.parseDate(value, this.format);
15342         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15343             v = Date.parseDate(value, 'Y-m-d');
15344         }
15345         if(!v && this.altFormats){
15346             if(!this.altFormatsArray){
15347                 this.altFormatsArray = this.altFormats.split("|");
15348             }
15349             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15350                 v = Date.parseDate(value, this.altFormatsArray[i]);
15351             }
15352         }
15353         return v;
15354     },
15355     
15356     formatDate : function(date, fmt)
15357     {   
15358         return (!date || !(date instanceof Date)) ?
15359         date : date.dateFormat(fmt || this.format);
15360     },
15361     
15362     onFocus : function()
15363     {
15364         Roo.bootstrap.DateField.superclass.onFocus.call(this);
15365         this.show();
15366     },
15367     
15368     onBlur : function()
15369     {
15370         Roo.bootstrap.DateField.superclass.onBlur.call(this);
15371         
15372         var d = this.inputEl().getValue();
15373         
15374         this.setValue(d);
15375                 
15376         this.hide();
15377     },
15378     
15379     show : function()
15380     {
15381         this.picker().show();
15382         this.update();
15383         this.place();
15384         
15385         this.fireEvent('show', this, this.date);
15386     },
15387     
15388     hide : function()
15389     {
15390         if(this.isInline) return;
15391         this.picker().hide();
15392         this.viewMode = this.startViewMode;
15393         this.showMode();
15394         
15395         this.fireEvent('hide', this, this.date);
15396         
15397     },
15398     
15399     onMousedown: function(e)
15400     {
15401         e.stopPropagation();
15402         e.preventDefault();
15403     },
15404     
15405     keyup: function(e)
15406     {
15407         Roo.bootstrap.DateField.superclass.keyup.call(this);
15408         this.update();
15409     },
15410
15411     setValue: function(v)
15412     {
15413         
15414         // v can be a string or a date..
15415         
15416         
15417         var d = new Date(this.parseDate(v) ).clearTime();
15418         
15419         if(isNaN(d.getTime())){
15420             this.date = this.viewDate = '';
15421             Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15422             return;
15423         }
15424         
15425         v = this.formatDate(d);
15426         
15427         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15428         
15429         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15430      
15431         this.update();
15432
15433         this.fireEvent('select', this, this.date);
15434         
15435     },
15436     
15437     getValue: function()
15438     {
15439         return this.formatDate(this.date);
15440     },
15441     
15442     fireKey: function(e)
15443     {
15444         if (!this.picker().isVisible()){
15445             if (e.keyCode == 27) // allow escape to hide and re-show picker
15446                 this.show();
15447             return;
15448         }
15449         
15450         var dateChanged = false,
15451         dir, day, month,
15452         newDate, newViewDate;
15453         
15454         switch(e.keyCode){
15455             case 27: // escape
15456                 this.hide();
15457                 e.preventDefault();
15458                 break;
15459             case 37: // left
15460             case 39: // right
15461                 if (!this.keyboardNavigation) break;
15462                 dir = e.keyCode == 37 ? -1 : 1;
15463                 
15464                 if (e.ctrlKey){
15465                     newDate = this.moveYear(this.date, dir);
15466                     newViewDate = this.moveYear(this.viewDate, dir);
15467                 } else if (e.shiftKey){
15468                     newDate = this.moveMonth(this.date, dir);
15469                     newViewDate = this.moveMonth(this.viewDate, dir);
15470                 } else {
15471                     newDate = new Date(this.date);
15472                     newDate.setUTCDate(this.date.getUTCDate() + dir);
15473                     newViewDate = new Date(this.viewDate);
15474                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15475                 }
15476                 if (this.dateWithinRange(newDate)){
15477                     this.date = newDate;
15478                     this.viewDate = newViewDate;
15479                     this.setValue(this.formatDate(this.date));
15480 //                    this.update();
15481                     e.preventDefault();
15482                     dateChanged = true;
15483                 }
15484                 break;
15485             case 38: // up
15486             case 40: // down
15487                 if (!this.keyboardNavigation) break;
15488                 dir = e.keyCode == 38 ? -1 : 1;
15489                 if (e.ctrlKey){
15490                     newDate = this.moveYear(this.date, dir);
15491                     newViewDate = this.moveYear(this.viewDate, dir);
15492                 } else if (e.shiftKey){
15493                     newDate = this.moveMonth(this.date, dir);
15494                     newViewDate = this.moveMonth(this.viewDate, dir);
15495                 } else {
15496                     newDate = new Date(this.date);
15497                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15498                     newViewDate = new Date(this.viewDate);
15499                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15500                 }
15501                 if (this.dateWithinRange(newDate)){
15502                     this.date = newDate;
15503                     this.viewDate = newViewDate;
15504                     this.setValue(this.formatDate(this.date));
15505 //                    this.update();
15506                     e.preventDefault();
15507                     dateChanged = true;
15508                 }
15509                 break;
15510             case 13: // enter
15511                 this.setValue(this.formatDate(this.date));
15512                 this.hide();
15513                 e.preventDefault();
15514                 break;
15515             case 9: // tab
15516                 this.setValue(this.formatDate(this.date));
15517                 this.hide();
15518                 break;
15519             case 16: // shift
15520             case 17: // ctrl
15521             case 18: // alt
15522                 break;
15523             default :
15524                 this.hide();
15525                 
15526         }
15527     },
15528     
15529     
15530     onClick: function(e) 
15531     {
15532         e.stopPropagation();
15533         e.preventDefault();
15534         
15535         var target = e.getTarget();
15536         
15537         if(target.nodeName.toLowerCase() === 'i'){
15538             target = Roo.get(target).dom.parentNode;
15539         }
15540         
15541         var nodeName = target.nodeName;
15542         var className = target.className;
15543         var html = target.innerHTML;
15544         //Roo.log(nodeName);
15545         
15546         switch(nodeName.toLowerCase()) {
15547             case 'th':
15548                 switch(className) {
15549                     case 'switch':
15550                         this.showMode(1);
15551                         break;
15552                     case 'prev':
15553                     case 'next':
15554                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15555                         switch(this.viewMode){
15556                                 case 0:
15557                                         this.viewDate = this.moveMonth(this.viewDate, dir);
15558                                         break;
15559                                 case 1:
15560                                 case 2:
15561                                         this.viewDate = this.moveYear(this.viewDate, dir);
15562                                         break;
15563                         }
15564                         this.fill();
15565                         break;
15566                     case 'today':
15567                         var date = new Date();
15568                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15569 //                        this.fill()
15570                         this.setValue(this.formatDate(this.date));
15571                         
15572                         this.hide();
15573                         break;
15574                 }
15575                 break;
15576             case 'span':
15577                 if (className.indexOf('disabled') < 0) {
15578                     this.viewDate.setUTCDate(1);
15579                     if (className.indexOf('month') > -1) {
15580                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15581                     } else {
15582                         var year = parseInt(html, 10) || 0;
15583                         this.viewDate.setUTCFullYear(year);
15584                         
15585                     }
15586                     
15587                     if(this.singleMode){
15588                         this.setValue(this.formatDate(this.viewDate));
15589                         this.hide();
15590                         return;
15591                     }
15592                     
15593                     this.showMode(-1);
15594                     this.fill();
15595                 }
15596                 break;
15597                 
15598             case 'td':
15599                 //Roo.log(className);
15600                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15601                     var day = parseInt(html, 10) || 1;
15602                     var year = this.viewDate.getUTCFullYear(),
15603                         month = this.viewDate.getUTCMonth();
15604
15605                     if (className.indexOf('old') > -1) {
15606                         if(month === 0 ){
15607                             month = 11;
15608                             year -= 1;
15609                         }else{
15610                             month -= 1;
15611                         }
15612                     } else if (className.indexOf('new') > -1) {
15613                         if (month == 11) {
15614                             month = 0;
15615                             year += 1;
15616                         } else {
15617                             month += 1;
15618                         }
15619                     }
15620                     //Roo.log([year,month,day]);
15621                     this.date = this.UTCDate(year, month, day,0,0,0,0);
15622                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15623 //                    this.fill();
15624                     //Roo.log(this.formatDate(this.date));
15625                     this.setValue(this.formatDate(this.date));
15626                     this.hide();
15627                 }
15628                 break;
15629         }
15630     },
15631     
15632     setStartDate: function(startDate)
15633     {
15634         this.startDate = startDate || -Infinity;
15635         if (this.startDate !== -Infinity) {
15636             this.startDate = this.parseDate(this.startDate);
15637         }
15638         this.update();
15639         this.updateNavArrows();
15640     },
15641
15642     setEndDate: function(endDate)
15643     {
15644         this.endDate = endDate || Infinity;
15645         if (this.endDate !== Infinity) {
15646             this.endDate = this.parseDate(this.endDate);
15647         }
15648         this.update();
15649         this.updateNavArrows();
15650     },
15651     
15652     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15653     {
15654         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15655         if (typeof(this.daysOfWeekDisabled) !== 'object') {
15656             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15657         }
15658         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15659             return parseInt(d, 10);
15660         });
15661         this.update();
15662         this.updateNavArrows();
15663     },
15664     
15665     updateNavArrows: function() 
15666     {
15667         if(this.singleMode){
15668             return;
15669         }
15670         
15671         var d = new Date(this.viewDate),
15672         year = d.getUTCFullYear(),
15673         month = d.getUTCMonth();
15674         
15675         Roo.each(this.picker().select('.prev', true).elements, function(v){
15676             v.show();
15677             switch (this.viewMode) {
15678                 case 0:
15679
15680                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15681                         v.hide();
15682                     }
15683                     break;
15684                 case 1:
15685                 case 2:
15686                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15687                         v.hide();
15688                     }
15689                     break;
15690             }
15691         });
15692         
15693         Roo.each(this.picker().select('.next', true).elements, function(v){
15694             v.show();
15695             switch (this.viewMode) {
15696                 case 0:
15697
15698                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15699                         v.hide();
15700                     }
15701                     break;
15702                 case 1:
15703                 case 2:
15704                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15705                         v.hide();
15706                     }
15707                     break;
15708             }
15709         })
15710     },
15711     
15712     moveMonth: function(date, dir)
15713     {
15714         if (!dir) return date;
15715         var new_date = new Date(date.valueOf()),
15716         day = new_date.getUTCDate(),
15717         month = new_date.getUTCMonth(),
15718         mag = Math.abs(dir),
15719         new_month, test;
15720         dir = dir > 0 ? 1 : -1;
15721         if (mag == 1){
15722             test = dir == -1
15723             // If going back one month, make sure month is not current month
15724             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15725             ? function(){
15726                 return new_date.getUTCMonth() == month;
15727             }
15728             // If going forward one month, make sure month is as expected
15729             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15730             : function(){
15731                 return new_date.getUTCMonth() != new_month;
15732             };
15733             new_month = month + dir;
15734             new_date.setUTCMonth(new_month);
15735             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15736             if (new_month < 0 || new_month > 11)
15737                 new_month = (new_month + 12) % 12;
15738         } else {
15739             // For magnitudes >1, move one month at a time...
15740             for (var i=0; i<mag; i++)
15741                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15742                 new_date = this.moveMonth(new_date, dir);
15743             // ...then reset the day, keeping it in the new month
15744             new_month = new_date.getUTCMonth();
15745             new_date.setUTCDate(day);
15746             test = function(){
15747                 return new_month != new_date.getUTCMonth();
15748             };
15749         }
15750         // Common date-resetting loop -- if date is beyond end of month, make it
15751         // end of month
15752         while (test()){
15753             new_date.setUTCDate(--day);
15754             new_date.setUTCMonth(new_month);
15755         }
15756         return new_date;
15757     },
15758
15759     moveYear: function(date, dir)
15760     {
15761         return this.moveMonth(date, dir*12);
15762     },
15763
15764     dateWithinRange: function(date)
15765     {
15766         return date >= this.startDate && date <= this.endDate;
15767     },
15768
15769     
15770     remove: function() 
15771     {
15772         this.picker().remove();
15773     }
15774    
15775 });
15776
15777 Roo.apply(Roo.bootstrap.DateField,  {
15778     
15779     head : {
15780         tag: 'thead',
15781         cn: [
15782         {
15783             tag: 'tr',
15784             cn: [
15785             {
15786                 tag: 'th',
15787                 cls: 'prev',
15788                 html: '<i class="fa fa-arrow-left"/>'
15789             },
15790             {
15791                 tag: 'th',
15792                 cls: 'switch',
15793                 colspan: '5'
15794             },
15795             {
15796                 tag: 'th',
15797                 cls: 'next',
15798                 html: '<i class="fa fa-arrow-right"/>'
15799             }
15800
15801             ]
15802         }
15803         ]
15804     },
15805     
15806     content : {
15807         tag: 'tbody',
15808         cn: [
15809         {
15810             tag: 'tr',
15811             cn: [
15812             {
15813                 tag: 'td',
15814                 colspan: '7'
15815             }
15816             ]
15817         }
15818         ]
15819     },
15820     
15821     footer : {
15822         tag: 'tfoot',
15823         cn: [
15824         {
15825             tag: 'tr',
15826             cn: [
15827             {
15828                 tag: 'th',
15829                 colspan: '7',
15830                 cls: 'today'
15831             }
15832                     
15833             ]
15834         }
15835         ]
15836     },
15837     
15838     dates:{
15839         en: {
15840             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15841             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15842             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15843             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15844             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15845             today: "Today"
15846         }
15847     },
15848     
15849     modes: [
15850     {
15851         clsName: 'days',
15852         navFnc: 'Month',
15853         navStep: 1
15854     },
15855     {
15856         clsName: 'months',
15857         navFnc: 'FullYear',
15858         navStep: 1
15859     },
15860     {
15861         clsName: 'years',
15862         navFnc: 'FullYear',
15863         navStep: 10
15864     }]
15865 });
15866
15867 Roo.apply(Roo.bootstrap.DateField,  {
15868   
15869     template : {
15870         tag: 'div',
15871         cls: 'datepicker dropdown-menu roo-dynamic',
15872         cn: [
15873         {
15874             tag: 'div',
15875             cls: 'datepicker-days',
15876             cn: [
15877             {
15878                 tag: 'table',
15879                 cls: 'table-condensed',
15880                 cn:[
15881                 Roo.bootstrap.DateField.head,
15882                 {
15883                     tag: 'tbody'
15884                 },
15885                 Roo.bootstrap.DateField.footer
15886                 ]
15887             }
15888             ]
15889         },
15890         {
15891             tag: 'div',
15892             cls: 'datepicker-months',
15893             cn: [
15894             {
15895                 tag: 'table',
15896                 cls: 'table-condensed',
15897                 cn:[
15898                 Roo.bootstrap.DateField.head,
15899                 Roo.bootstrap.DateField.content,
15900                 Roo.bootstrap.DateField.footer
15901                 ]
15902             }
15903             ]
15904         },
15905         {
15906             tag: 'div',
15907             cls: 'datepicker-years',
15908             cn: [
15909             {
15910                 tag: 'table',
15911                 cls: 'table-condensed',
15912                 cn:[
15913                 Roo.bootstrap.DateField.head,
15914                 Roo.bootstrap.DateField.content,
15915                 Roo.bootstrap.DateField.footer
15916                 ]
15917             }
15918             ]
15919         }
15920         ]
15921     }
15922 });
15923
15924  
15925
15926  /*
15927  * - LGPL
15928  *
15929  * TimeField
15930  * 
15931  */
15932
15933 /**
15934  * @class Roo.bootstrap.TimeField
15935  * @extends Roo.bootstrap.Input
15936  * Bootstrap DateField class
15937  * 
15938  * 
15939  * @constructor
15940  * Create a new TimeField
15941  * @param {Object} config The config object
15942  */
15943
15944 Roo.bootstrap.TimeField = function(config){
15945     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15946     this.addEvents({
15947             /**
15948              * @event show
15949              * Fires when this field show.
15950              * @param {Roo.bootstrap.DateField} thisthis
15951              * @param {Mixed} date The date value
15952              */
15953             show : true,
15954             /**
15955              * @event show
15956              * Fires when this field hide.
15957              * @param {Roo.bootstrap.DateField} this
15958              * @param {Mixed} date The date value
15959              */
15960             hide : true,
15961             /**
15962              * @event select
15963              * Fires when select a date.
15964              * @param {Roo.bootstrap.DateField} this
15965              * @param {Mixed} date The date value
15966              */
15967             select : true
15968         });
15969 };
15970
15971 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
15972     
15973     /**
15974      * @cfg {String} format
15975      * The default time format string which can be overriden for localization support.  The format must be
15976      * valid according to {@link Date#parseDate} (defaults to 'H:i').
15977      */
15978     format : "H:i",
15979        
15980     onRender: function(ct, position)
15981     {
15982         
15983         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
15984                 
15985         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
15986         
15987         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15988         
15989         this.pop = this.picker().select('>.datepicker-time',true).first();
15990         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15991         
15992         this.picker().on('mousedown', this.onMousedown, this);
15993         this.picker().on('click', this.onClick, this);
15994         
15995         this.picker().addClass('datepicker-dropdown');
15996     
15997         this.fillTime();
15998         this.update();
15999             
16000         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16001         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16002         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16003         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16004         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16005         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16006
16007     },
16008     
16009     fireKey: function(e){
16010         if (!this.picker().isVisible()){
16011             if (e.keyCode == 27) { // allow escape to hide and re-show picker
16012                 this.show();
16013             }
16014             return;
16015         }
16016
16017         e.preventDefault();
16018         
16019         switch(e.keyCode){
16020             case 27: // escape
16021                 this.hide();
16022                 break;
16023             case 37: // left
16024             case 39: // right
16025                 this.onTogglePeriod();
16026                 break;
16027             case 38: // up
16028                 this.onIncrementMinutes();
16029                 break;
16030             case 40: // down
16031                 this.onDecrementMinutes();
16032                 break;
16033             case 13: // enter
16034             case 9: // tab
16035                 this.setTime();
16036                 break;
16037         }
16038     },
16039     
16040     onClick: function(e) {
16041         e.stopPropagation();
16042         e.preventDefault();
16043     },
16044     
16045     picker : function()
16046     {
16047         return this.el.select('.datepicker', true).first();
16048     },
16049     
16050     fillTime: function()
16051     {    
16052         var time = this.pop.select('tbody', true).first();
16053         
16054         time.dom.innerHTML = '';
16055         
16056         time.createChild({
16057             tag: 'tr',
16058             cn: [
16059                 {
16060                     tag: 'td',
16061                     cn: [
16062                         {
16063                             tag: 'a',
16064                             href: '#',
16065                             cls: 'btn',
16066                             cn: [
16067                                 {
16068                                     tag: 'span',
16069                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
16070                                 }
16071                             ]
16072                         } 
16073                     ]
16074                 },
16075                 {
16076                     tag: 'td',
16077                     cls: 'separator'
16078                 },
16079                 {
16080                     tag: 'td',
16081                     cn: [
16082                         {
16083                             tag: 'a',
16084                             href: '#',
16085                             cls: 'btn',
16086                             cn: [
16087                                 {
16088                                     tag: 'span',
16089                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
16090                                 }
16091                             ]
16092                         }
16093                     ]
16094                 },
16095                 {
16096                     tag: 'td',
16097                     cls: 'separator'
16098                 }
16099             ]
16100         });
16101         
16102         time.createChild({
16103             tag: 'tr',
16104             cn: [
16105                 {
16106                     tag: 'td',
16107                     cn: [
16108                         {
16109                             tag: 'span',
16110                             cls: 'timepicker-hour',
16111                             html: '00'
16112                         }  
16113                     ]
16114                 },
16115                 {
16116                     tag: 'td',
16117                     cls: 'separator',
16118                     html: ':'
16119                 },
16120                 {
16121                     tag: 'td',
16122                     cn: [
16123                         {
16124                             tag: 'span',
16125                             cls: 'timepicker-minute',
16126                             html: '00'
16127                         }  
16128                     ]
16129                 },
16130                 {
16131                     tag: 'td',
16132                     cls: 'separator'
16133                 },
16134                 {
16135                     tag: 'td',
16136                     cn: [
16137                         {
16138                             tag: 'button',
16139                             type: 'button',
16140                             cls: 'btn btn-primary period',
16141                             html: 'AM'
16142                             
16143                         }
16144                     ]
16145                 }
16146             ]
16147         });
16148         
16149         time.createChild({
16150             tag: 'tr',
16151             cn: [
16152                 {
16153                     tag: 'td',
16154                     cn: [
16155                         {
16156                             tag: 'a',
16157                             href: '#',
16158                             cls: 'btn',
16159                             cn: [
16160                                 {
16161                                     tag: 'span',
16162                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
16163                                 }
16164                             ]
16165                         }
16166                     ]
16167                 },
16168                 {
16169                     tag: 'td',
16170                     cls: 'separator'
16171                 },
16172                 {
16173                     tag: 'td',
16174                     cn: [
16175                         {
16176                             tag: 'a',
16177                             href: '#',
16178                             cls: 'btn',
16179                             cn: [
16180                                 {
16181                                     tag: 'span',
16182                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
16183                                 }
16184                             ]
16185                         }
16186                     ]
16187                 },
16188                 {
16189                     tag: 'td',
16190                     cls: 'separator'
16191                 }
16192             ]
16193         });
16194         
16195     },
16196     
16197     update: function()
16198     {
16199         
16200         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16201         
16202         this.fill();
16203     },
16204     
16205     fill: function() 
16206     {
16207         var hours = this.time.getHours();
16208         var minutes = this.time.getMinutes();
16209         var period = 'AM';
16210         
16211         if(hours > 11){
16212             period = 'PM';
16213         }
16214         
16215         if(hours == 0){
16216             hours = 12;
16217         }
16218         
16219         
16220         if(hours > 12){
16221             hours = hours - 12;
16222         }
16223         
16224         if(hours < 10){
16225             hours = '0' + hours;
16226         }
16227         
16228         if(minutes < 10){
16229             minutes = '0' + minutes;
16230         }
16231         
16232         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16233         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16234         this.pop.select('button', true).first().dom.innerHTML = period;
16235         
16236     },
16237     
16238     place: function()
16239     {   
16240         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16241         
16242         var cls = ['bottom'];
16243         
16244         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16245             cls.pop();
16246             cls.push('top');
16247         }
16248         
16249         cls.push('right');
16250         
16251         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16252             cls.pop();
16253             cls.push('left');
16254         }
16255         
16256         this.picker().addClass(cls.join('-'));
16257         
16258         var _this = this;
16259         
16260         Roo.each(cls, function(c){
16261             if(c == 'bottom'){
16262                 _this.picker().setTop(_this.inputEl().getHeight());
16263                 return;
16264             }
16265             if(c == 'top'){
16266                 _this.picker().setTop(0 - _this.picker().getHeight());
16267                 return;
16268             }
16269             
16270             if(c == 'left'){
16271                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16272                 return;
16273             }
16274             if(c == 'right'){
16275                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16276                 return;
16277             }
16278         });
16279         
16280     },
16281   
16282     onFocus : function()
16283     {
16284         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16285         this.show();
16286     },
16287     
16288     onBlur : function()
16289     {
16290         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16291         this.hide();
16292     },
16293     
16294     show : function()
16295     {
16296         this.picker().show();
16297         this.pop.show();
16298         this.update();
16299         this.place();
16300         
16301         this.fireEvent('show', this, this.date);
16302     },
16303     
16304     hide : function()
16305     {
16306         this.picker().hide();
16307         this.pop.hide();
16308         
16309         this.fireEvent('hide', this, this.date);
16310     },
16311     
16312     setTime : function()
16313     {
16314         this.hide();
16315         this.setValue(this.time.format(this.format));
16316         
16317         this.fireEvent('select', this, this.date);
16318         
16319         
16320     },
16321     
16322     onMousedown: function(e){
16323         e.stopPropagation();
16324         e.preventDefault();
16325     },
16326     
16327     onIncrementHours: function()
16328     {
16329         Roo.log('onIncrementHours');
16330         this.time = this.time.add(Date.HOUR, 1);
16331         this.update();
16332         
16333     },
16334     
16335     onDecrementHours: function()
16336     {
16337         Roo.log('onDecrementHours');
16338         this.time = this.time.add(Date.HOUR, -1);
16339         this.update();
16340     },
16341     
16342     onIncrementMinutes: function()
16343     {
16344         Roo.log('onIncrementMinutes');
16345         this.time = this.time.add(Date.MINUTE, 1);
16346         this.update();
16347     },
16348     
16349     onDecrementMinutes: function()
16350     {
16351         Roo.log('onDecrementMinutes');
16352         this.time = this.time.add(Date.MINUTE, -1);
16353         this.update();
16354     },
16355     
16356     onTogglePeriod: function()
16357     {
16358         Roo.log('onTogglePeriod');
16359         this.time = this.time.add(Date.HOUR, 12);
16360         this.update();
16361     }
16362     
16363    
16364 });
16365
16366 Roo.apply(Roo.bootstrap.TimeField,  {
16367     
16368     content : {
16369         tag: 'tbody',
16370         cn: [
16371             {
16372                 tag: 'tr',
16373                 cn: [
16374                 {
16375                     tag: 'td',
16376                     colspan: '7'
16377                 }
16378                 ]
16379             }
16380         ]
16381     },
16382     
16383     footer : {
16384         tag: 'tfoot',
16385         cn: [
16386             {
16387                 tag: 'tr',
16388                 cn: [
16389                 {
16390                     tag: 'th',
16391                     colspan: '7',
16392                     cls: '',
16393                     cn: [
16394                         {
16395                             tag: 'button',
16396                             cls: 'btn btn-info ok',
16397                             html: 'OK'
16398                         }
16399                     ]
16400                 }
16401
16402                 ]
16403             }
16404         ]
16405     }
16406 });
16407
16408 Roo.apply(Roo.bootstrap.TimeField,  {
16409   
16410     template : {
16411         tag: 'div',
16412         cls: 'datepicker dropdown-menu',
16413         cn: [
16414             {
16415                 tag: 'div',
16416                 cls: 'datepicker-time',
16417                 cn: [
16418                 {
16419                     tag: 'table',
16420                     cls: 'table-condensed',
16421                     cn:[
16422                     Roo.bootstrap.TimeField.content,
16423                     Roo.bootstrap.TimeField.footer
16424                     ]
16425                 }
16426                 ]
16427             }
16428         ]
16429     }
16430 });
16431
16432  
16433
16434  /*
16435  * - LGPL
16436  *
16437  * MonthField
16438  * 
16439  */
16440
16441 /**
16442  * @class Roo.bootstrap.MonthField
16443  * @extends Roo.bootstrap.Input
16444  * Bootstrap MonthField class
16445  * 
16446  * @cfg {String} language default en
16447  * 
16448  * @constructor
16449  * Create a new MonthField
16450  * @param {Object} config The config object
16451  */
16452
16453 Roo.bootstrap.MonthField = function(config){
16454     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16455     
16456     this.addEvents({
16457         /**
16458          * @event show
16459          * Fires when this field show.
16460          * @param {Roo.bootstrap.MonthField} this
16461          * @param {Mixed} date The date value
16462          */
16463         show : true,
16464         /**
16465          * @event show
16466          * Fires when this field hide.
16467          * @param {Roo.bootstrap.MonthField} this
16468          * @param {Mixed} date The date value
16469          */
16470         hide : true,
16471         /**
16472          * @event select
16473          * Fires when select a date.
16474          * @param {Roo.bootstrap.MonthField} this
16475          * @param {String} oldvalue The old value
16476          * @param {String} newvalue The new value
16477          */
16478         select : true
16479     });
16480 };
16481
16482 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
16483     
16484     onRender: function(ct, position)
16485     {
16486         
16487         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16488         
16489         this.language = this.language || 'en';
16490         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16491         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16492         
16493         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16494         this.isInline = false;
16495         this.isInput = true;
16496         this.component = this.el.select('.add-on', true).first() || false;
16497         this.component = (this.component && this.component.length === 0) ? false : this.component;
16498         this.hasInput = this.component && this.inputEL().length;
16499         
16500         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16501         
16502         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16503         
16504         this.picker().on('mousedown', this.onMousedown, this);
16505         this.picker().on('click', this.onClick, this);
16506         
16507         this.picker().addClass('datepicker-dropdown');
16508         
16509         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16510             v.setStyle('width', '189px');
16511         });
16512         
16513         this.fillMonths();
16514         
16515         this.update();
16516         
16517         if(this.isInline) {
16518             this.show();
16519         }
16520         
16521     },
16522     
16523     setValue: function(v, suppressEvent)
16524     {   
16525         var o = this.getValue();
16526         
16527         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16528         
16529         this.update();
16530
16531         if(suppressEvent !== true){
16532             this.fireEvent('select', this, o, v);
16533         }
16534         
16535     },
16536     
16537     getValue: function()
16538     {
16539         return this.value;
16540     },
16541     
16542     onClick: function(e) 
16543     {
16544         e.stopPropagation();
16545         e.preventDefault();
16546         
16547         var target = e.getTarget();
16548         
16549         if(target.nodeName.toLowerCase() === 'i'){
16550             target = Roo.get(target).dom.parentNode;
16551         }
16552         
16553         var nodeName = target.nodeName;
16554         var className = target.className;
16555         var html = target.innerHTML;
16556         
16557         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16558             return;
16559         }
16560         
16561         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16562         
16563         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16564         
16565         this.hide();
16566                         
16567     },
16568     
16569     picker : function()
16570     {
16571         return this.pickerEl;
16572     },
16573     
16574     fillMonths: function()
16575     {    
16576         var i = 0;
16577         var months = this.picker().select('>.datepicker-months td', true).first();
16578         
16579         months.dom.innerHTML = '';
16580         
16581         while (i < 12) {
16582             var month = {
16583                 tag: 'span',
16584                 cls: 'month',
16585                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16586             }
16587             
16588             months.createChild(month);
16589         }
16590         
16591     },
16592     
16593     update: function()
16594     {
16595         var _this = this;
16596         
16597         if(typeof(this.vIndex) == 'undefined' && this.value.length){
16598             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16599         }
16600         
16601         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16602             e.removeClass('active');
16603             
16604             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16605                 e.addClass('active');
16606             }
16607         })
16608     },
16609     
16610     place: function()
16611     {
16612         if(this.isInline) return;
16613         
16614         this.picker().removeClass(['bottom', 'top']);
16615         
16616         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16617             /*
16618              * place to the top of element!
16619              *
16620              */
16621             
16622             this.picker().addClass('top');
16623             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16624             
16625             return;
16626         }
16627         
16628         this.picker().addClass('bottom');
16629         
16630         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16631     },
16632     
16633     onFocus : function()
16634     {
16635         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16636         this.show();
16637     },
16638     
16639     onBlur : function()
16640     {
16641         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16642         
16643         var d = this.inputEl().getValue();
16644         
16645         this.setValue(d);
16646                 
16647         this.hide();
16648     },
16649     
16650     show : function()
16651     {
16652         this.picker().show();
16653         this.picker().select('>.datepicker-months', true).first().show();
16654         this.update();
16655         this.place();
16656         
16657         this.fireEvent('show', this, this.date);
16658     },
16659     
16660     hide : function()
16661     {
16662         if(this.isInline) return;
16663         this.picker().hide();
16664         this.fireEvent('hide', this, this.date);
16665         
16666     },
16667     
16668     onMousedown: function(e)
16669     {
16670         e.stopPropagation();
16671         e.preventDefault();
16672     },
16673     
16674     keyup: function(e)
16675     {
16676         Roo.bootstrap.MonthField.superclass.keyup.call(this);
16677         this.update();
16678     },
16679
16680     fireKey: function(e)
16681     {
16682         if (!this.picker().isVisible()){
16683             if (e.keyCode == 27) // allow escape to hide and re-show picker
16684                 this.show();
16685             return;
16686         }
16687         
16688         var dir;
16689         
16690         switch(e.keyCode){
16691             case 27: // escape
16692                 this.hide();
16693                 e.preventDefault();
16694                 break;
16695             case 37: // left
16696             case 39: // right
16697                 dir = e.keyCode == 37 ? -1 : 1;
16698                 
16699                 this.vIndex = this.vIndex + dir;
16700                 
16701                 if(this.vIndex < 0){
16702                     this.vIndex = 0;
16703                 }
16704                 
16705                 if(this.vIndex > 11){
16706                     this.vIndex = 11;
16707                 }
16708                 
16709                 if(isNaN(this.vIndex)){
16710                     this.vIndex = 0;
16711                 }
16712                 
16713                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16714                 
16715                 break;
16716             case 38: // up
16717             case 40: // down
16718                 
16719                 dir = e.keyCode == 38 ? -1 : 1;
16720                 
16721                 this.vIndex = this.vIndex + dir * 4;
16722                 
16723                 if(this.vIndex < 0){
16724                     this.vIndex = 0;
16725                 }
16726                 
16727                 if(this.vIndex > 11){
16728                     this.vIndex = 11;
16729                 }
16730                 
16731                 if(isNaN(this.vIndex)){
16732                     this.vIndex = 0;
16733                 }
16734                 
16735                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16736                 break;
16737                 
16738             case 13: // enter
16739                 
16740                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16741                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16742                 }
16743                 
16744                 this.hide();
16745                 e.preventDefault();
16746                 break;
16747             case 9: // tab
16748                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16749                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16750                 }
16751                 this.hide();
16752                 break;
16753             case 16: // shift
16754             case 17: // ctrl
16755             case 18: // alt
16756                 break;
16757             default :
16758                 this.hide();
16759                 
16760         }
16761     },
16762     
16763     remove: function() 
16764     {
16765         this.picker().remove();
16766     }
16767    
16768 });
16769
16770 Roo.apply(Roo.bootstrap.MonthField,  {
16771     
16772     content : {
16773         tag: 'tbody',
16774         cn: [
16775         {
16776             tag: 'tr',
16777             cn: [
16778             {
16779                 tag: 'td',
16780                 colspan: '7'
16781             }
16782             ]
16783         }
16784         ]
16785     },
16786     
16787     dates:{
16788         en: {
16789             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16790             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16791         }
16792     }
16793 });
16794
16795 Roo.apply(Roo.bootstrap.MonthField,  {
16796   
16797     template : {
16798         tag: 'div',
16799         cls: 'datepicker dropdown-menu roo-dynamic',
16800         cn: [
16801             {
16802                 tag: 'div',
16803                 cls: 'datepicker-months',
16804                 cn: [
16805                 {
16806                     tag: 'table',
16807                     cls: 'table-condensed',
16808                     cn:[
16809                         Roo.bootstrap.DateField.content
16810                     ]
16811                 }
16812                 ]
16813             }
16814         ]
16815     }
16816 });
16817
16818  
16819
16820  
16821  /*
16822  * - LGPL
16823  *
16824  * CheckBox
16825  * 
16826  */
16827
16828 /**
16829  * @class Roo.bootstrap.CheckBox
16830  * @extends Roo.bootstrap.Input
16831  * Bootstrap CheckBox class
16832  * 
16833  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16834  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16835  * @cfg {String} boxLabel The text that appears beside the checkbox
16836  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16837  * @cfg {Boolean} checked initnal the element
16838  * @cfg {Boolean} inline inline the element (default false)
16839  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16840  * 
16841  * @constructor
16842  * Create a new CheckBox
16843  * @param {Object} config The config object
16844  */
16845
16846 Roo.bootstrap.CheckBox = function(config){
16847     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16848    
16849     this.addEvents({
16850         /**
16851         * @event check
16852         * Fires when the element is checked or unchecked.
16853         * @param {Roo.bootstrap.CheckBox} this This input
16854         * @param {Boolean} checked The new checked value
16855         */
16856        check : true
16857     });
16858     
16859 };
16860
16861 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
16862   
16863     inputType: 'checkbox',
16864     inputValue: 1,
16865     valueOff: 0,
16866     boxLabel: false,
16867     checked: false,
16868     weight : false,
16869     inline: false,
16870     
16871     getAutoCreate : function()
16872     {
16873         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16874         
16875         var id = Roo.id();
16876         
16877         var cfg = {};
16878         
16879         cfg.cls = 'form-group ' + this.inputType; //input-group
16880         
16881         if(this.inline){
16882             cfg.cls += ' ' + this.inputType + '-inline';
16883         }
16884         
16885         var input =  {
16886             tag: 'input',
16887             id : id,
16888             type : this.inputType,
16889             value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16890             cls : 'roo-' + this.inputType, //'form-box',
16891             placeholder : this.placeholder || ''
16892             
16893         };
16894         
16895         if (this.weight) { // Validity check?
16896             cfg.cls += " " + this.inputType + "-" + this.weight;
16897         }
16898         
16899         if (this.disabled) {
16900             input.disabled=true;
16901         }
16902         
16903         if(this.checked){
16904             input.checked = this.checked;
16905         }
16906         
16907         if (this.name) {
16908             input.name = this.name;
16909         }
16910         
16911         if (this.size) {
16912             input.cls += ' input-' + this.size;
16913         }
16914         
16915         var settings=this;
16916         
16917         ['xs','sm','md','lg'].map(function(size){
16918             if (settings[size]) {
16919                 cfg.cls += ' col-' + size + '-' + settings[size];
16920             }
16921         });
16922         
16923         var inputblock = input;
16924          
16925         if (this.before || this.after) {
16926             
16927             inputblock = {
16928                 cls : 'input-group',
16929                 cn :  [] 
16930             };
16931             
16932             if (this.before) {
16933                 inputblock.cn.push({
16934                     tag :'span',
16935                     cls : 'input-group-addon',
16936                     html : this.before
16937                 });
16938             }
16939             
16940             inputblock.cn.push(input);
16941             
16942             if (this.after) {
16943                 inputblock.cn.push({
16944                     tag :'span',
16945                     cls : 'input-group-addon',
16946                     html : this.after
16947                 });
16948             }
16949             
16950         }
16951         
16952         if (align ==='left' && this.fieldLabel.length) {
16953                 Roo.log("left and has label");
16954                 cfg.cn = [
16955                     
16956                     {
16957                         tag: 'label',
16958                         'for' :  id,
16959                         cls : 'control-label col-md-' + this.labelWidth,
16960                         html : this.fieldLabel
16961                         
16962                     },
16963                     {
16964                         cls : "col-md-" + (12 - this.labelWidth), 
16965                         cn: [
16966                             inputblock
16967                         ]
16968                     }
16969                     
16970                 ];
16971         } else if ( this.fieldLabel.length) {
16972                 Roo.log(" label");
16973                 cfg.cn = [
16974                    
16975                     {
16976                         tag: this.boxLabel ? 'span' : 'label',
16977                         'for': id,
16978                         cls: 'control-label box-input-label',
16979                         //cls : 'input-group-addon',
16980                         html : this.fieldLabel
16981                         
16982                     },
16983                     
16984                     inputblock
16985                     
16986                 ];
16987
16988         } else {
16989             
16990                 Roo.log(" no label && no align");
16991                 cfg.cn = [  inputblock ] ;
16992                 
16993                 
16994         }
16995         if(this.boxLabel){
16996              var boxLabelCfg = {
16997                 tag: 'label',
16998                 //'for': id, // box label is handled by onclick - so no for...
16999                 cls: 'box-label',
17000                 html: this.boxLabel
17001             }
17002             
17003             if(this.tooltip){
17004                 boxLabelCfg.tooltip = this.tooltip;
17005             }
17006              
17007             cfg.cn.push(boxLabelCfg);
17008         }
17009         
17010         
17011        
17012         return cfg;
17013         
17014     },
17015     
17016     /**
17017      * return the real input element.
17018      */
17019     inputEl: function ()
17020     {
17021         return this.el.select('input.roo-' + this.inputType,true).first();
17022     },
17023     
17024     labelEl: function()
17025     {
17026         return this.el.select('label.control-label',true).first();
17027     },
17028     /* depricated... */
17029     
17030     label: function()
17031     {
17032         return this.labelEl();
17033     },
17034     
17035     initEvents : function()
17036     {
17037 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17038         
17039         this.inputEl().on('click', this.onClick,  this);
17040         
17041         if (this.boxLabel) { 
17042             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
17043         }
17044         
17045         this.startValue = this.getValue();
17046         
17047         if(this.groupId){
17048             Roo.bootstrap.CheckBox.register(this);
17049         }
17050     },
17051     
17052     onClick : function()
17053     {   
17054         this.setChecked(!this.checked);
17055     },
17056     
17057     setChecked : function(state,suppressEvent)
17058     {
17059         this.startValue = this.getValue();
17060         
17061         if(this.inputType == 'radio'){
17062             
17063             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17064                 e.dom.checked = false;
17065             });
17066             
17067             this.inputEl().dom.checked = true;
17068             
17069             this.inputEl().dom.value = this.inputValue;
17070             
17071             if(suppressEvent !== true){
17072                 this.fireEvent('check', this, true);
17073             }
17074             
17075             this.validate();
17076             
17077             return;
17078         }
17079         
17080         this.checked = state;
17081         
17082         this.inputEl().dom.checked = state;
17083         
17084         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17085         
17086         if(suppressEvent !== true){
17087             this.fireEvent('check', this, state);
17088         }
17089         
17090         this.validate();
17091     },
17092     
17093     getValue : function()
17094     {
17095         if(this.inputType == 'radio'){
17096             return this.getGroupValue();
17097         }
17098         
17099         return this.inputEl().getValue();
17100         
17101     },
17102     
17103     getGroupValue : function()
17104     {
17105         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17106             return '';
17107         }
17108         
17109         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17110     },
17111     
17112     setValue : function(v,suppressEvent)
17113     {
17114         if(this.inputType == 'radio'){
17115             this.setGroupValue(v, suppressEvent);
17116             return;
17117         }
17118         
17119         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17120         
17121         this.validate();
17122     },
17123     
17124     setGroupValue : function(v, suppressEvent)
17125     {
17126         this.startValue = this.getValue();
17127         
17128         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17129             e.dom.checked = false;
17130             
17131             if(e.dom.value == v){
17132                 e.dom.checked = true;
17133             }
17134         });
17135         
17136         if(suppressEvent !== true){
17137             this.fireEvent('check', this, true);
17138         }
17139
17140         this.validate();
17141         
17142         return;
17143     },
17144     
17145     validate : function()
17146     {
17147         if(
17148                 this.disabled || 
17149                 (this.inputType == 'radio' && this.validateRadio()) ||
17150                 (this.inputType == 'checkbox' && this.validateCheckbox())
17151         ){
17152             this.markValid();
17153             return true;
17154         }
17155         
17156         this.markInvalid();
17157         return false;
17158     },
17159     
17160     validateRadio : function()
17161     {
17162         var valid = false;
17163         
17164         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17165             if(!e.dom.checked){
17166                 return;
17167             }
17168             
17169             valid = true;
17170             
17171             return false;
17172         });
17173         
17174         return valid;
17175     },
17176     
17177     validateCheckbox : function()
17178     {
17179         if(!this.groupId){
17180             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17181         }
17182         
17183         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17184         
17185         if(!group){
17186             return false;
17187         }
17188         
17189         var r = false;
17190         
17191         for(var i in group){
17192             if(r){
17193                 break;
17194             }
17195             
17196             r = (group[i].getValue() == group[i].inputValue) ? true : false;
17197         }
17198         
17199         return r;
17200     },
17201     
17202     /**
17203      * Mark this field as valid
17204      */
17205     markValid : function()
17206     {
17207         if(this.allowBlank){
17208             return;
17209         }
17210         
17211         var _this = this;
17212         
17213         this.fireEvent('valid', this);
17214         
17215         if(this.inputType == 'radio'){
17216             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17217                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17218                 e.findParent('.form-group', false, true).addClass(_this.validClass);
17219             });
17220             
17221             return;
17222         }
17223         
17224         if(!this.groupId){
17225             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17226             this.el.findParent('.form-group', false, true).addClass(this.validClass);
17227             return;
17228         }
17229         
17230         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17231             
17232         if(!group){
17233             return;
17234         }
17235         
17236         for(var i in group){
17237             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17238             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17239         }
17240     },
17241     
17242      /**
17243      * Mark this field as invalid
17244      * @param {String} msg The validation message
17245      */
17246     markInvalid : function(msg)
17247     {
17248         if(this.allowBlank){
17249             return;
17250         }
17251         
17252         var _this = this;
17253         
17254         this.fireEvent('invalid', this, msg);
17255         
17256         if(this.inputType == 'radio'){
17257             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17258                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17259                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17260             });
17261             
17262             return;
17263         }
17264         
17265         if(!this.groupId){
17266             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17267             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17268             return;
17269         }
17270         
17271         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17272             
17273         if(!group){
17274             return;
17275         }
17276         
17277         for(var i in group){
17278             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17279             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17280         }
17281         
17282     }
17283     
17284 });
17285
17286 Roo.apply(Roo.bootstrap.CheckBox, {
17287     
17288     groups: {},
17289     
17290      /**
17291     * register a CheckBox Group
17292     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17293     */
17294     register : function(checkbox)
17295     {
17296         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17297             this.groups[checkbox.groupId] = {};
17298         }
17299         
17300         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17301             return;
17302         }
17303         
17304         this.groups[checkbox.groupId][checkbox.name] = checkbox;
17305         
17306     },
17307     /**
17308     * fetch a CheckBox Group based on the group ID
17309     * @param {string} the group ID
17310     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17311     */
17312     get: function(groupId) {
17313         if (typeof(this.groups[groupId]) == 'undefined') {
17314             return false;
17315         }
17316         
17317         return this.groups[groupId] ;
17318     }
17319     
17320     
17321 });
17322 /*
17323  * - LGPL
17324  *
17325  * Radio
17326  *
17327  *
17328  * not inline
17329  *<div class="radio">
17330   <label>
17331     <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17332     Option one is this and that&mdash;be sure to include why it's great
17333   </label>
17334 </div>
17335  *
17336  *
17337  *inline
17338  *<span>
17339  *<label class="radio-inline">fieldLabel</label>
17340  *<label class="radio-inline">
17341   <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17342 </label>
17343 <span>
17344  * 
17345  * 
17346  */
17347
17348 /**
17349  * @class Roo.bootstrap.Radio
17350  * @extends Roo.bootstrap.CheckBox
17351  * Bootstrap Radio class
17352
17353  * @constructor
17354  * Create a new Radio
17355  * @param {Object} config The config object
17356  */
17357
17358 Roo.bootstrap.Radio = function(config){
17359     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17360    
17361 };
17362
17363 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
17364     
17365     inputType: 'radio',
17366     inputValue: '',
17367     valueOff: '',
17368     
17369     getAutoCreate : function()
17370     {
17371         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17372         align = align || 'left'; // default...
17373         
17374         
17375         
17376         var id = Roo.id();
17377         
17378         var cfg = {
17379                 tag : this.inline ? 'span' : 'div',
17380                 cls : '',
17381                 cn : []
17382         };
17383         
17384         var inline = this.inline ? ' radio-inline' : '';
17385         
17386         var lbl = {
17387                 tag: 'label' ,
17388                 // does not need for, as we wrap the input with it..
17389                 'for' : id,
17390                 cls : 'control-label box-label' + inline,
17391                 cn : []
17392         };
17393         var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17394         
17395         var fieldLabel = {
17396             tag: 'label' ,
17397             //cls : 'control-label' + inline,
17398             html : this.fieldLabel,
17399             style : 'width:' +  labelWidth  + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17400         };
17401         
17402  
17403         
17404         
17405         var input =  {
17406             tag: 'input',
17407             id : id,
17408             type : this.inputType,
17409             //value : (!this.checked) ? this.valueOff : this.inputValue,
17410             value : this.inputValue,
17411             cls : 'roo-radio',
17412             placeholder : this.placeholder || '' // ?? needed????
17413             
17414         };
17415         if (this.weight) { // Validity check?
17416             input.cls += " radio-" + this.weight;
17417         }
17418         if (this.disabled) {
17419             input.disabled=true;
17420         }
17421         
17422         if(this.checked){
17423             input.checked = this.checked;
17424         }
17425         
17426         if (this.name) {
17427             input.name = this.name;
17428         }
17429         
17430         if (this.size) {
17431             input.cls += ' input-' + this.size;
17432         }
17433         
17434         //?? can span's inline have a width??
17435         
17436         var settings=this;
17437         ['xs','sm','md','lg'].map(function(size){
17438             if (settings[size]) {
17439                 cfg.cls += ' col-' + size + '-' + settings[size];
17440             }
17441         });
17442         
17443         var inputblock = input;
17444         
17445         if (this.before || this.after) {
17446             
17447             inputblock = {
17448                 cls : 'input-group',
17449                 tag : 'span',
17450                 cn :  [] 
17451             };
17452             if (this.before) {
17453                 inputblock.cn.push({
17454                     tag :'span',
17455                     cls : 'input-group-addon',
17456                     html : this.before
17457                 });
17458             }
17459             inputblock.cn.push(input);
17460             if (this.after) {
17461                 inputblock.cn.push({
17462                     tag :'span',
17463                     cls : 'input-group-addon',
17464                     html : this.after
17465                 });
17466             }
17467             
17468         };
17469         
17470         
17471         if (this.fieldLabel && this.fieldLabel.length) {
17472             cfg.cn.push(fieldLabel);
17473         }
17474        
17475         // normal bootstrap puts the input inside the label.
17476         // however with our styled version - it has to go after the input.
17477        
17478         //lbl.cn.push(inputblock);
17479         
17480         var lblwrap =  {
17481             tag: 'span',
17482             cls: 'radio' + inline,
17483             cn: [
17484                 inputblock,
17485                 lbl
17486             ]
17487         };
17488         
17489         cfg.cn.push( lblwrap);
17490         
17491         if(this.boxLabel){
17492             lbl.cn.push({
17493                 tag: 'span',
17494                 html: this.boxLabel
17495             })
17496         }
17497          
17498         
17499         return cfg;
17500         
17501     },
17502     
17503     initEvents : function()
17504     {
17505 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17506         
17507         this.inputEl().on('click', this.onClick,  this);
17508         if (this.boxLabel) {
17509             Roo.log('find label')
17510             this.el.select('span.radio label span',true).first().on('click', this.onClick,  this);
17511         }
17512         
17513     },
17514     
17515     inputEl: function ()
17516     {
17517         return this.el.select('input.roo-radio',true).first();
17518     },
17519     onClick : function()
17520     {   
17521         Roo.log("click");
17522         this.setChecked(true);
17523     },
17524     
17525     setChecked : function(state,suppressEvent)
17526     {
17527         if(state){
17528             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17529                 v.dom.checked = false;
17530             });
17531         }
17532         Roo.log(this.inputEl().dom);
17533         this.checked = state;
17534         this.inputEl().dom.checked = state;
17535         
17536         if(suppressEvent !== true){
17537             this.fireEvent('check', this, state);
17538         }
17539         
17540         //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17541         
17542     },
17543     
17544     getGroupValue : function()
17545     {
17546         var value = '';
17547         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17548             if(v.dom.checked == true){
17549                 value = v.dom.value;
17550             }
17551         });
17552         
17553         return value;
17554     },
17555     
17556     /**
17557      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
17558      * @return {Mixed} value The field value
17559      */
17560     getValue : function(){
17561         return this.getGroupValue();
17562     }
17563     
17564 });
17565
17566  
17567 //<script type="text/javascript">
17568
17569 /*
17570  * Based  Ext JS Library 1.1.1
17571  * Copyright(c) 2006-2007, Ext JS, LLC.
17572  * LGPL
17573  *
17574  */
17575  
17576 /**
17577  * @class Roo.HtmlEditorCore
17578  * @extends Roo.Component
17579  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17580  *
17581  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17582  */
17583
17584 Roo.HtmlEditorCore = function(config){
17585     
17586     
17587     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17588     
17589     
17590     this.addEvents({
17591         /**
17592          * @event initialize
17593          * Fires when the editor is fully initialized (including the iframe)
17594          * @param {Roo.HtmlEditorCore} this
17595          */
17596         initialize: true,
17597         /**
17598          * @event activate
17599          * Fires when the editor is first receives the focus. Any insertion must wait
17600          * until after this event.
17601          * @param {Roo.HtmlEditorCore} this
17602          */
17603         activate: true,
17604          /**
17605          * @event beforesync
17606          * Fires before the textarea is updated with content from the editor iframe. Return false
17607          * to cancel the sync.
17608          * @param {Roo.HtmlEditorCore} this
17609          * @param {String} html
17610          */
17611         beforesync: true,
17612          /**
17613          * @event beforepush
17614          * Fires before the iframe editor is updated with content from the textarea. Return false
17615          * to cancel the push.
17616          * @param {Roo.HtmlEditorCore} this
17617          * @param {String} html
17618          */
17619         beforepush: true,
17620          /**
17621          * @event sync
17622          * Fires when the textarea is updated with content from the editor iframe.
17623          * @param {Roo.HtmlEditorCore} this
17624          * @param {String} html
17625          */
17626         sync: true,
17627          /**
17628          * @event push
17629          * Fires when the iframe editor is updated with content from the textarea.
17630          * @param {Roo.HtmlEditorCore} this
17631          * @param {String} html
17632          */
17633         push: true,
17634         
17635         /**
17636          * @event editorevent
17637          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17638          * @param {Roo.HtmlEditorCore} this
17639          */
17640         editorevent: true
17641         
17642     });
17643     
17644     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17645     
17646     // defaults : white / black...
17647     this.applyBlacklists();
17648     
17649     
17650     
17651 };
17652
17653
17654 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
17655
17656
17657      /**
17658      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
17659      */
17660     
17661     owner : false,
17662     
17663      /**
17664      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17665      *                        Roo.resizable.
17666      */
17667     resizable : false,
17668      /**
17669      * @cfg {Number} height (in pixels)
17670      */   
17671     height: 300,
17672    /**
17673      * @cfg {Number} width (in pixels)
17674      */   
17675     width: 500,
17676     
17677     /**
17678      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17679      * 
17680      */
17681     stylesheets: false,
17682     
17683     // id of frame..
17684     frameId: false,
17685     
17686     // private properties
17687     validationEvent : false,
17688     deferHeight: true,
17689     initialized : false,
17690     activated : false,
17691     sourceEditMode : false,
17692     onFocus : Roo.emptyFn,
17693     iframePad:3,
17694     hideMode:'offsets',
17695     
17696     clearUp: true,
17697     
17698     // blacklist + whitelisted elements..
17699     black: false,
17700     white: false,
17701      
17702     
17703
17704     /**
17705      * Protected method that will not generally be called directly. It
17706      * is called when the editor initializes the iframe with HTML contents. Override this method if you
17707      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17708      */
17709     getDocMarkup : function(){
17710         // body styles..
17711         var st = '';
17712         
17713         // inherit styels from page...?? 
17714         if (this.stylesheets === false) {
17715             
17716             Roo.get(document.head).select('style').each(function(node) {
17717                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17718             });
17719             
17720             Roo.get(document.head).select('link').each(function(node) { 
17721                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17722             });
17723             
17724         } else if (!this.stylesheets.length) {
17725                 // simple..
17726                 st = '<style type="text/css">' +
17727                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17728                    '</style>';
17729         } else { 
17730             
17731         }
17732         
17733         st +=  '<style type="text/css">' +
17734             'IMG { cursor: pointer } ' +
17735         '</style>';
17736
17737         
17738         return '<html><head>' + st  +
17739             //<style type="text/css">' +
17740             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17741             //'</style>' +
17742             ' </head><body class="roo-htmleditor-body"></body></html>';
17743     },
17744
17745     // private
17746     onRender : function(ct, position)
17747     {
17748         var _t = this;
17749         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17750         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17751         
17752         
17753         this.el.dom.style.border = '0 none';
17754         this.el.dom.setAttribute('tabIndex', -1);
17755         this.el.addClass('x-hidden hide');
17756         
17757         
17758         
17759         if(Roo.isIE){ // fix IE 1px bogus margin
17760             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17761         }
17762        
17763         
17764         this.frameId = Roo.id();
17765         
17766          
17767         
17768         var iframe = this.owner.wrap.createChild({
17769             tag: 'iframe',
17770             cls: 'form-control', // bootstrap..
17771             id: this.frameId,
17772             name: this.frameId,
17773             frameBorder : 'no',
17774             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
17775         }, this.el
17776         );
17777         
17778         
17779         this.iframe = iframe.dom;
17780
17781          this.assignDocWin();
17782         
17783         this.doc.designMode = 'on';
17784        
17785         this.doc.open();
17786         this.doc.write(this.getDocMarkup());
17787         this.doc.close();
17788
17789         
17790         var task = { // must defer to wait for browser to be ready
17791             run : function(){
17792                 //console.log("run task?" + this.doc.readyState);
17793                 this.assignDocWin();
17794                 if(this.doc.body || this.doc.readyState == 'complete'){
17795                     try {
17796                         this.doc.designMode="on";
17797                     } catch (e) {
17798                         return;
17799                     }
17800                     Roo.TaskMgr.stop(task);
17801                     this.initEditor.defer(10, this);
17802                 }
17803             },
17804             interval : 10,
17805             duration: 10000,
17806             scope: this
17807         };
17808         Roo.TaskMgr.start(task);
17809
17810     },
17811
17812     // private
17813     onResize : function(w, h)
17814     {
17815          Roo.log('resize: ' +w + ',' + h );
17816         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17817         if(!this.iframe){
17818             return;
17819         }
17820         if(typeof w == 'number'){
17821             
17822             this.iframe.style.width = w + 'px';
17823         }
17824         if(typeof h == 'number'){
17825             
17826             this.iframe.style.height = h + 'px';
17827             if(this.doc){
17828                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17829             }
17830         }
17831         
17832     },
17833
17834     /**
17835      * Toggles the editor between standard and source edit mode.
17836      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17837      */
17838     toggleSourceEdit : function(sourceEditMode){
17839         
17840         this.sourceEditMode = sourceEditMode === true;
17841         
17842         if(this.sourceEditMode){
17843  
17844             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
17845             
17846         }else{
17847             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17848             //this.iframe.className = '';
17849             this.deferFocus();
17850         }
17851         //this.setSize(this.owner.wrap.getSize());
17852         //this.fireEvent('editmodechange', this, this.sourceEditMode);
17853     },
17854
17855     
17856   
17857
17858     /**
17859      * Protected method that will not generally be called directly. If you need/want
17860      * custom HTML cleanup, this is the method you should override.
17861      * @param {String} html The HTML to be cleaned
17862      * return {String} The cleaned HTML
17863      */
17864     cleanHtml : function(html){
17865         html = String(html);
17866         if(html.length > 5){
17867             if(Roo.isSafari){ // strip safari nonsense
17868                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17869             }
17870         }
17871         if(html == '&nbsp;'){
17872             html = '';
17873         }
17874         return html;
17875     },
17876
17877     /**
17878      * HTML Editor -> Textarea
17879      * Protected method that will not generally be called directly. Syncs the contents
17880      * of the editor iframe with the textarea.
17881      */
17882     syncValue : function(){
17883         if(this.initialized){
17884             var bd = (this.doc.body || this.doc.documentElement);
17885             //this.cleanUpPaste(); -- this is done else where and causes havoc..
17886             var html = bd.innerHTML;
17887             if(Roo.isSafari){
17888                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17889                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17890                 if(m && m[1]){
17891                     html = '<div style="'+m[0]+'">' + html + '</div>';
17892                 }
17893             }
17894             html = this.cleanHtml(html);
17895             // fix up the special chars.. normaly like back quotes in word...
17896             // however we do not want to do this with chinese..
17897             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17898                 var cc = b.charCodeAt();
17899                 if (
17900                     (cc >= 0x4E00 && cc < 0xA000 ) ||
17901                     (cc >= 0x3400 && cc < 0x4E00 ) ||
17902                     (cc >= 0xf900 && cc < 0xfb00 )
17903                 ) {
17904                         return b;
17905                 }
17906                 return "&#"+cc+";" 
17907             });
17908             if(this.owner.fireEvent('beforesync', this, html) !== false){
17909                 this.el.dom.value = html;
17910                 this.owner.fireEvent('sync', this, html);
17911             }
17912         }
17913     },
17914
17915     /**
17916      * Protected method that will not generally be called directly. Pushes the value of the textarea
17917      * into the iframe editor.
17918      */
17919     pushValue : function(){
17920         if(this.initialized){
17921             var v = this.el.dom.value.trim();
17922             
17923 //            if(v.length < 1){
17924 //                v = '&#160;';
17925 //            }
17926             
17927             if(this.owner.fireEvent('beforepush', this, v) !== false){
17928                 var d = (this.doc.body || this.doc.documentElement);
17929                 d.innerHTML = v;
17930                 this.cleanUpPaste();
17931                 this.el.dom.value = d.innerHTML;
17932                 this.owner.fireEvent('push', this, v);
17933             }
17934         }
17935     },
17936
17937     // private
17938     deferFocus : function(){
17939         this.focus.defer(10, this);
17940     },
17941
17942     // doc'ed in Field
17943     focus : function(){
17944         if(this.win && !this.sourceEditMode){
17945             this.win.focus();
17946         }else{
17947             this.el.focus();
17948         }
17949     },
17950     
17951     assignDocWin: function()
17952     {
17953         var iframe = this.iframe;
17954         
17955          if(Roo.isIE){
17956             this.doc = iframe.contentWindow.document;
17957             this.win = iframe.contentWindow;
17958         } else {
17959 //            if (!Roo.get(this.frameId)) {
17960 //                return;
17961 //            }
17962 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17963 //            this.win = Roo.get(this.frameId).dom.contentWindow;
17964             
17965             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17966                 return;
17967             }
17968             
17969             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17970             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17971         }
17972     },
17973     
17974     // private
17975     initEditor : function(){
17976         //console.log("INIT EDITOR");
17977         this.assignDocWin();
17978         
17979         
17980         
17981         this.doc.designMode="on";
17982         this.doc.open();
17983         this.doc.write(this.getDocMarkup());
17984         this.doc.close();
17985         
17986         var dbody = (this.doc.body || this.doc.documentElement);
17987         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
17988         // this copies styles from the containing element into thsi one..
17989         // not sure why we need all of this..
17990         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
17991         
17992         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
17993         //ss['background-attachment'] = 'fixed'; // w3c
17994         dbody.bgProperties = 'fixed'; // ie
17995         //Roo.DomHelper.applyStyles(dbody, ss);
17996         Roo.EventManager.on(this.doc, {
17997             //'mousedown': this.onEditorEvent,
17998             'mouseup': this.onEditorEvent,
17999             'dblclick': this.onEditorEvent,
18000             'click': this.onEditorEvent,
18001             'keyup': this.onEditorEvent,
18002             buffer:100,
18003             scope: this
18004         });
18005         if(Roo.isGecko){
18006             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18007         }
18008         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18009             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18010         }
18011         this.initialized = true;
18012
18013         this.owner.fireEvent('initialize', this);
18014         this.pushValue();
18015     },
18016
18017     // private
18018     onDestroy : function(){
18019         
18020         
18021         
18022         if(this.rendered){
18023             
18024             //for (var i =0; i < this.toolbars.length;i++) {
18025             //    // fixme - ask toolbars for heights?
18026             //    this.toolbars[i].onDestroy();
18027            // }
18028             
18029             //this.wrap.dom.innerHTML = '';
18030             //this.wrap.remove();
18031         }
18032     },
18033
18034     // private
18035     onFirstFocus : function(){
18036         
18037         this.assignDocWin();
18038         
18039         
18040         this.activated = true;
18041          
18042     
18043         if(Roo.isGecko){ // prevent silly gecko errors
18044             this.win.focus();
18045             var s = this.win.getSelection();
18046             if(!s.focusNode || s.focusNode.nodeType != 3){
18047                 var r = s.getRangeAt(0);
18048                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18049                 r.collapse(true);
18050                 this.deferFocus();
18051             }
18052             try{
18053                 this.execCmd('useCSS', true);
18054                 this.execCmd('styleWithCSS', false);
18055             }catch(e){}
18056         }
18057         this.owner.fireEvent('activate', this);
18058     },
18059
18060     // private
18061     adjustFont: function(btn){
18062         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18063         //if(Roo.isSafari){ // safari
18064         //    adjust *= 2;
18065        // }
18066         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18067         if(Roo.isSafari){ // safari
18068             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18069             v =  (v < 10) ? 10 : v;
18070             v =  (v > 48) ? 48 : v;
18071             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18072             
18073         }
18074         
18075         
18076         v = Math.max(1, v+adjust);
18077         
18078         this.execCmd('FontSize', v  );
18079     },
18080
18081     onEditorEvent : function(e){
18082         this.owner.fireEvent('editorevent', this, e);
18083       //  this.updateToolbar();
18084         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18085     },
18086
18087     insertTag : function(tg)
18088     {
18089         // could be a bit smarter... -> wrap the current selected tRoo..
18090         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18091             
18092             range = this.createRange(this.getSelection());
18093             var wrappingNode = this.doc.createElement(tg.toLowerCase());
18094             wrappingNode.appendChild(range.extractContents());
18095             range.insertNode(wrappingNode);
18096
18097             return;
18098             
18099             
18100             
18101         }
18102         this.execCmd("formatblock",   tg);
18103         
18104     },
18105     
18106     insertText : function(txt)
18107     {
18108         
18109         
18110         var range = this.createRange();
18111         range.deleteContents();
18112                //alert(Sender.getAttribute('label'));
18113                
18114         range.insertNode(this.doc.createTextNode(txt));
18115     } ,
18116     
18117      
18118
18119     /**
18120      * Executes a Midas editor command on the editor document and performs necessary focus and
18121      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18122      * @param {String} cmd The Midas command
18123      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18124      */
18125     relayCmd : function(cmd, value){
18126         this.win.focus();
18127         this.execCmd(cmd, value);
18128         this.owner.fireEvent('editorevent', this);
18129         //this.updateToolbar();
18130         this.owner.deferFocus();
18131     },
18132
18133     /**
18134      * Executes a Midas editor command directly on the editor document.
18135      * For visual commands, you should use {@link #relayCmd} instead.
18136      * <b>This should only be called after the editor is initialized.</b>
18137      * @param {String} cmd The Midas command
18138      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18139      */
18140     execCmd : function(cmd, value){
18141         this.doc.execCommand(cmd, false, value === undefined ? null : value);
18142         this.syncValue();
18143     },
18144  
18145  
18146    
18147     /**
18148      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18149      * to insert tRoo.
18150      * @param {String} text | dom node.. 
18151      */
18152     insertAtCursor : function(text)
18153     {
18154         
18155         
18156         
18157         if(!this.activated){
18158             return;
18159         }
18160         /*
18161         if(Roo.isIE){
18162             this.win.focus();
18163             var r = this.doc.selection.createRange();
18164             if(r){
18165                 r.collapse(true);
18166                 r.pasteHTML(text);
18167                 this.syncValue();
18168                 this.deferFocus();
18169             
18170             }
18171             return;
18172         }
18173         */
18174         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18175             this.win.focus();
18176             
18177             
18178             // from jquery ui (MIT licenced)
18179             var range, node;
18180             var win = this.win;
18181             
18182             if (win.getSelection && win.getSelection().getRangeAt) {
18183                 range = win.getSelection().getRangeAt(0);
18184                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18185                 range.insertNode(node);
18186             } else if (win.document.selection && win.document.selection.createRange) {
18187                 // no firefox support
18188                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18189                 win.document.selection.createRange().pasteHTML(txt);
18190             } else {
18191                 // no firefox support
18192                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18193                 this.execCmd('InsertHTML', txt);
18194             } 
18195             
18196             this.syncValue();
18197             
18198             this.deferFocus();
18199         }
18200     },
18201  // private
18202     mozKeyPress : function(e){
18203         if(e.ctrlKey){
18204             var c = e.getCharCode(), cmd;
18205           
18206             if(c > 0){
18207                 c = String.fromCharCode(c).toLowerCase();
18208                 switch(c){
18209                     case 'b':
18210                         cmd = 'bold';
18211                         break;
18212                     case 'i':
18213                         cmd = 'italic';
18214                         break;
18215                     
18216                     case 'u':
18217                         cmd = 'underline';
18218                         break;
18219                     
18220                     case 'v':
18221                         this.cleanUpPaste.defer(100, this);
18222                         return;
18223                         
18224                 }
18225                 if(cmd){
18226                     this.win.focus();
18227                     this.execCmd(cmd);
18228                     this.deferFocus();
18229                     e.preventDefault();
18230                 }
18231                 
18232             }
18233         }
18234     },
18235
18236     // private
18237     fixKeys : function(){ // load time branching for fastest keydown performance
18238         if(Roo.isIE){
18239             return function(e){
18240                 var k = e.getKey(), r;
18241                 if(k == e.TAB){
18242                     e.stopEvent();
18243                     r = this.doc.selection.createRange();
18244                     if(r){
18245                         r.collapse(true);
18246                         r.pasteHTML('&#160;&#160;&#160;&#160;');
18247                         this.deferFocus();
18248                     }
18249                     return;
18250                 }
18251                 
18252                 if(k == e.ENTER){
18253                     r = this.doc.selection.createRange();
18254                     if(r){
18255                         var target = r.parentElement();
18256                         if(!target || target.tagName.toLowerCase() != 'li'){
18257                             e.stopEvent();
18258                             r.pasteHTML('<br />');
18259                             r.collapse(false);
18260                             r.select();
18261                         }
18262                     }
18263                 }
18264                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18265                     this.cleanUpPaste.defer(100, this);
18266                     return;
18267                 }
18268                 
18269                 
18270             };
18271         }else if(Roo.isOpera){
18272             return function(e){
18273                 var k = e.getKey();
18274                 if(k == e.TAB){
18275                     e.stopEvent();
18276                     this.win.focus();
18277                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
18278                     this.deferFocus();
18279                 }
18280                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18281                     this.cleanUpPaste.defer(100, this);
18282                     return;
18283                 }
18284                 
18285             };
18286         }else if(Roo.isSafari){
18287             return function(e){
18288                 var k = e.getKey();
18289                 
18290                 if(k == e.TAB){
18291                     e.stopEvent();
18292                     this.execCmd('InsertText','\t');
18293                     this.deferFocus();
18294                     return;
18295                 }
18296                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18297                     this.cleanUpPaste.defer(100, this);
18298                     return;
18299                 }
18300                 
18301              };
18302         }
18303     }(),
18304     
18305     getAllAncestors: function()
18306     {
18307         var p = this.getSelectedNode();
18308         var a = [];
18309         if (!p) {
18310             a.push(p); // push blank onto stack..
18311             p = this.getParentElement();
18312         }
18313         
18314         
18315         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18316             a.push(p);
18317             p = p.parentNode;
18318         }
18319         a.push(this.doc.body);
18320         return a;
18321     },
18322     lastSel : false,
18323     lastSelNode : false,
18324     
18325     
18326     getSelection : function() 
18327     {
18328         this.assignDocWin();
18329         return Roo.isIE ? this.doc.selection : this.win.getSelection();
18330     },
18331     
18332     getSelectedNode: function() 
18333     {
18334         // this may only work on Gecko!!!
18335         
18336         // should we cache this!!!!
18337         
18338         
18339         
18340          
18341         var range = this.createRange(this.getSelection()).cloneRange();
18342         
18343         if (Roo.isIE) {
18344             var parent = range.parentElement();
18345             while (true) {
18346                 var testRange = range.duplicate();
18347                 testRange.moveToElementText(parent);
18348                 if (testRange.inRange(range)) {
18349                     break;
18350                 }
18351                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18352                     break;
18353                 }
18354                 parent = parent.parentElement;
18355             }
18356             return parent;
18357         }
18358         
18359         // is ancestor a text element.
18360         var ac =  range.commonAncestorContainer;
18361         if (ac.nodeType == 3) {
18362             ac = ac.parentNode;
18363         }
18364         
18365         var ar = ac.childNodes;
18366          
18367         var nodes = [];
18368         var other_nodes = [];
18369         var has_other_nodes = false;
18370         for (var i=0;i<ar.length;i++) {
18371             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
18372                 continue;
18373             }
18374             // fullly contained node.
18375             
18376             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18377                 nodes.push(ar[i]);
18378                 continue;
18379             }
18380             
18381             // probably selected..
18382             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18383                 other_nodes.push(ar[i]);
18384                 continue;
18385             }
18386             // outer..
18387             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
18388                 continue;
18389             }
18390             
18391             
18392             has_other_nodes = true;
18393         }
18394         if (!nodes.length && other_nodes.length) {
18395             nodes= other_nodes;
18396         }
18397         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18398             return false;
18399         }
18400         
18401         return nodes[0];
18402     },
18403     createRange: function(sel)
18404     {
18405         // this has strange effects when using with 
18406         // top toolbar - not sure if it's a great idea.
18407         //this.editor.contentWindow.focus();
18408         if (typeof sel != "undefined") {
18409             try {
18410                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18411             } catch(e) {
18412                 return this.doc.createRange();
18413             }
18414         } else {
18415             return this.doc.createRange();
18416         }
18417     },
18418     getParentElement: function()
18419     {
18420         
18421         this.assignDocWin();
18422         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18423         
18424         var range = this.createRange(sel);
18425          
18426         try {
18427             var p = range.commonAncestorContainer;
18428             while (p.nodeType == 3) { // text node
18429                 p = p.parentNode;
18430             }
18431             return p;
18432         } catch (e) {
18433             return null;
18434         }
18435     
18436     },
18437     /***
18438      *
18439      * Range intersection.. the hard stuff...
18440      *  '-1' = before
18441      *  '0' = hits..
18442      *  '1' = after.
18443      *         [ -- selected range --- ]
18444      *   [fail]                        [fail]
18445      *
18446      *    basically..
18447      *      if end is before start or  hits it. fail.
18448      *      if start is after end or hits it fail.
18449      *
18450      *   if either hits (but other is outside. - then it's not 
18451      *   
18452      *    
18453      **/
18454     
18455     
18456     // @see http://www.thismuchiknow.co.uk/?p=64.
18457     rangeIntersectsNode : function(range, node)
18458     {
18459         var nodeRange = node.ownerDocument.createRange();
18460         try {
18461             nodeRange.selectNode(node);
18462         } catch (e) {
18463             nodeRange.selectNodeContents(node);
18464         }
18465     
18466         var rangeStartRange = range.cloneRange();
18467         rangeStartRange.collapse(true);
18468     
18469         var rangeEndRange = range.cloneRange();
18470         rangeEndRange.collapse(false);
18471     
18472         var nodeStartRange = nodeRange.cloneRange();
18473         nodeStartRange.collapse(true);
18474     
18475         var nodeEndRange = nodeRange.cloneRange();
18476         nodeEndRange.collapse(false);
18477     
18478         return rangeStartRange.compareBoundaryPoints(
18479                  Range.START_TO_START, nodeEndRange) == -1 &&
18480                rangeEndRange.compareBoundaryPoints(
18481                  Range.START_TO_START, nodeStartRange) == 1;
18482         
18483          
18484     },
18485     rangeCompareNode : function(range, node)
18486     {
18487         var nodeRange = node.ownerDocument.createRange();
18488         try {
18489             nodeRange.selectNode(node);
18490         } catch (e) {
18491             nodeRange.selectNodeContents(node);
18492         }
18493         
18494         
18495         range.collapse(true);
18496     
18497         nodeRange.collapse(true);
18498      
18499         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18500         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
18501          
18502         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18503         
18504         var nodeIsBefore   =  ss == 1;
18505         var nodeIsAfter    = ee == -1;
18506         
18507         if (nodeIsBefore && nodeIsAfter)
18508             return 0; // outer
18509         if (!nodeIsBefore && nodeIsAfter)
18510             return 1; //right trailed.
18511         
18512         if (nodeIsBefore && !nodeIsAfter)
18513             return 2;  // left trailed.
18514         // fully contined.
18515         return 3;
18516     },
18517
18518     // private? - in a new class?
18519     cleanUpPaste :  function()
18520     {
18521         // cleans up the whole document..
18522         Roo.log('cleanuppaste');
18523         
18524         this.cleanUpChildren(this.doc.body);
18525         var clean = this.cleanWordChars(this.doc.body.innerHTML);
18526         if (clean != this.doc.body.innerHTML) {
18527             this.doc.body.innerHTML = clean;
18528         }
18529         
18530     },
18531     
18532     cleanWordChars : function(input) {// change the chars to hex code
18533         var he = Roo.HtmlEditorCore;
18534         
18535         var output = input;
18536         Roo.each(he.swapCodes, function(sw) { 
18537             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18538             
18539             output = output.replace(swapper, sw[1]);
18540         });
18541         
18542         return output;
18543     },
18544     
18545     
18546     cleanUpChildren : function (n)
18547     {
18548         if (!n.childNodes.length) {
18549             return;
18550         }
18551         for (var i = n.childNodes.length-1; i > -1 ; i--) {
18552            this.cleanUpChild(n.childNodes[i]);
18553         }
18554     },
18555     
18556     
18557         
18558     
18559     cleanUpChild : function (node)
18560     {
18561         var ed = this;
18562         //console.log(node);
18563         if (node.nodeName == "#text") {
18564             // clean up silly Windows -- stuff?
18565             return; 
18566         }
18567         if (node.nodeName == "#comment") {
18568             node.parentNode.removeChild(node);
18569             // clean up silly Windows -- stuff?
18570             return; 
18571         }
18572         var lcname = node.tagName.toLowerCase();
18573         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18574         // whitelist of tags..
18575         
18576         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18577             // remove node.
18578             node.parentNode.removeChild(node);
18579             return;
18580             
18581         }
18582         
18583         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18584         
18585         // remove <a name=....> as rendering on yahoo mailer is borked with this.
18586         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18587         
18588         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18589         //    remove_keep_children = true;
18590         //}
18591         
18592         if (remove_keep_children) {
18593             this.cleanUpChildren(node);
18594             // inserts everything just before this node...
18595             while (node.childNodes.length) {
18596                 var cn = node.childNodes[0];
18597                 node.removeChild(cn);
18598                 node.parentNode.insertBefore(cn, node);
18599             }
18600             node.parentNode.removeChild(node);
18601             return;
18602         }
18603         
18604         if (!node.attributes || !node.attributes.length) {
18605             this.cleanUpChildren(node);
18606             return;
18607         }
18608         
18609         function cleanAttr(n,v)
18610         {
18611             
18612             if (v.match(/^\./) || v.match(/^\//)) {
18613                 return;
18614             }
18615             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18616                 return;
18617             }
18618             if (v.match(/^#/)) {
18619                 return;
18620             }
18621 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18622             node.removeAttribute(n);
18623             
18624         }
18625         
18626         var cwhite = this.cwhite;
18627         var cblack = this.cblack;
18628             
18629         function cleanStyle(n,v)
18630         {
18631             if (v.match(/expression/)) { //XSS?? should we even bother..
18632                 node.removeAttribute(n);
18633                 return;
18634             }
18635             
18636             var parts = v.split(/;/);
18637             var clean = [];
18638             
18639             Roo.each(parts, function(p) {
18640                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18641                 if (!p.length) {
18642                     return true;
18643                 }
18644                 var l = p.split(':').shift().replace(/\s+/g,'');
18645                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18646                 
18647                 if ( cwhite.length && cblack.indexOf(l) > -1) {
18648 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18649                     //node.removeAttribute(n);
18650                     return true;
18651                 }
18652                 //Roo.log()
18653                 // only allow 'c whitelisted system attributes'
18654                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
18655 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18656                     //node.removeAttribute(n);
18657                     return true;
18658                 }
18659                 
18660                 
18661                  
18662                 
18663                 clean.push(p);
18664                 return true;
18665             });
18666             if (clean.length) { 
18667                 node.setAttribute(n, clean.join(';'));
18668             } else {
18669                 node.removeAttribute(n);
18670             }
18671             
18672         }
18673         
18674         
18675         for (var i = node.attributes.length-1; i > -1 ; i--) {
18676             var a = node.attributes[i];
18677             //console.log(a);
18678             
18679             if (a.name.toLowerCase().substr(0,2)=='on')  {
18680                 node.removeAttribute(a.name);
18681                 continue;
18682             }
18683             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18684                 node.removeAttribute(a.name);
18685                 continue;
18686             }
18687             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18688                 cleanAttr(a.name,a.value); // fixme..
18689                 continue;
18690             }
18691             if (a.name == 'style') {
18692                 cleanStyle(a.name,a.value);
18693                 continue;
18694             }
18695             /// clean up MS crap..
18696             // tecnically this should be a list of valid class'es..
18697             
18698             
18699             if (a.name == 'class') {
18700                 if (a.value.match(/^Mso/)) {
18701                     node.className = '';
18702                 }
18703                 
18704                 if (a.value.match(/body/)) {
18705                     node.className = '';
18706                 }
18707                 continue;
18708             }
18709             
18710             // style cleanup!?
18711             // class cleanup?
18712             
18713         }
18714         
18715         
18716         this.cleanUpChildren(node);
18717         
18718         
18719     },
18720     /**
18721      * Clean up MS wordisms...
18722      */
18723     cleanWord : function(node)
18724     {
18725         var _t = this;
18726         var cleanWordChildren = function()
18727         {
18728             if (!node.childNodes.length) {
18729                 return;
18730             }
18731             for (var i = node.childNodes.length-1; i > -1 ; i--) {
18732                _t.cleanWord(node.childNodes[i]);
18733             }
18734         }
18735         
18736         
18737         if (!node) {
18738             this.cleanWord(this.doc.body);
18739             return;
18740         }
18741         if (node.nodeName == "#text") {
18742             // clean up silly Windows -- stuff?
18743             return; 
18744         }
18745         if (node.nodeName == "#comment") {
18746             node.parentNode.removeChild(node);
18747             // clean up silly Windows -- stuff?
18748             return; 
18749         }
18750         
18751         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18752             node.parentNode.removeChild(node);
18753             return;
18754         }
18755         
18756         // remove - but keep children..
18757         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18758             while (node.childNodes.length) {
18759                 var cn = node.childNodes[0];
18760                 node.removeChild(cn);
18761                 node.parentNode.insertBefore(cn, node);
18762             }
18763             node.parentNode.removeChild(node);
18764             cleanWordChildren();
18765             return;
18766         }
18767         // clean styles
18768         if (node.className.length) {
18769             
18770             var cn = node.className.split(/\W+/);
18771             var cna = [];
18772             Roo.each(cn, function(cls) {
18773                 if (cls.match(/Mso[a-zA-Z]+/)) {
18774                     return;
18775                 }
18776                 cna.push(cls);
18777             });
18778             node.className = cna.length ? cna.join(' ') : '';
18779             if (!cna.length) {
18780                 node.removeAttribute("class");
18781             }
18782         }
18783         
18784         if (node.hasAttribute("lang")) {
18785             node.removeAttribute("lang");
18786         }
18787         
18788         if (node.hasAttribute("style")) {
18789             
18790             var styles = node.getAttribute("style").split(";");
18791             var nstyle = [];
18792             Roo.each(styles, function(s) {
18793                 if (!s.match(/:/)) {
18794                     return;
18795                 }
18796                 var kv = s.split(":");
18797                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18798                     return;
18799                 }
18800                 // what ever is left... we allow.
18801                 nstyle.push(s);
18802             });
18803             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18804             if (!nstyle.length) {
18805                 node.removeAttribute('style');
18806             }
18807         }
18808         
18809         cleanWordChildren();
18810         
18811         
18812     },
18813     domToHTML : function(currentElement, depth, nopadtext) {
18814         
18815         depth = depth || 0;
18816         nopadtext = nopadtext || false;
18817     
18818         if (!currentElement) {
18819             return this.domToHTML(this.doc.body);
18820         }
18821         
18822         //Roo.log(currentElement);
18823         var j;
18824         var allText = false;
18825         var nodeName = currentElement.nodeName;
18826         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18827         
18828         if  (nodeName == '#text') {
18829             
18830             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18831         }
18832         
18833         
18834         var ret = '';
18835         if (nodeName != 'BODY') {
18836              
18837             var i = 0;
18838             // Prints the node tagName, such as <A>, <IMG>, etc
18839             if (tagName) {
18840                 var attr = [];
18841                 for(i = 0; i < currentElement.attributes.length;i++) {
18842                     // quoting?
18843                     var aname = currentElement.attributes.item(i).name;
18844                     if (!currentElement.attributes.item(i).value.length) {
18845                         continue;
18846                     }
18847                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18848                 }
18849                 
18850                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18851             } 
18852             else {
18853                 
18854                 // eack
18855             }
18856         } else {
18857             tagName = false;
18858         }
18859         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18860             return ret;
18861         }
18862         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18863             nopadtext = true;
18864         }
18865         
18866         
18867         // Traverse the tree
18868         i = 0;
18869         var currentElementChild = currentElement.childNodes.item(i);
18870         var allText = true;
18871         var innerHTML  = '';
18872         lastnode = '';
18873         while (currentElementChild) {
18874             // Formatting code (indent the tree so it looks nice on the screen)
18875             var nopad = nopadtext;
18876             if (lastnode == 'SPAN') {
18877                 nopad  = true;
18878             }
18879             // text
18880             if  (currentElementChild.nodeName == '#text') {
18881                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18882                 toadd = nopadtext ? toadd : toadd.trim();
18883                 if (!nopad && toadd.length > 80) {
18884                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
18885                 }
18886                 innerHTML  += toadd;
18887                 
18888                 i++;
18889                 currentElementChild = currentElement.childNodes.item(i);
18890                 lastNode = '';
18891                 continue;
18892             }
18893             allText = false;
18894             
18895             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
18896                 
18897             // Recursively traverse the tree structure of the child node
18898             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
18899             lastnode = currentElementChild.nodeName;
18900             i++;
18901             currentElementChild=currentElement.childNodes.item(i);
18902         }
18903         
18904         ret += innerHTML;
18905         
18906         if (!allText) {
18907                 // The remaining code is mostly for formatting the tree
18908             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
18909         }
18910         
18911         
18912         if (tagName) {
18913             ret+= "</"+tagName+">";
18914         }
18915         return ret;
18916         
18917     },
18918         
18919     applyBlacklists : function()
18920     {
18921         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
18922         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
18923         
18924         this.white = [];
18925         this.black = [];
18926         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18927             if (b.indexOf(tag) > -1) {
18928                 return;
18929             }
18930             this.white.push(tag);
18931             
18932         }, this);
18933         
18934         Roo.each(w, function(tag) {
18935             if (b.indexOf(tag) > -1) {
18936                 return;
18937             }
18938             if (this.white.indexOf(tag) > -1) {
18939                 return;
18940             }
18941             this.white.push(tag);
18942             
18943         }, this);
18944         
18945         
18946         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18947             if (w.indexOf(tag) > -1) {
18948                 return;
18949             }
18950             this.black.push(tag);
18951             
18952         }, this);
18953         
18954         Roo.each(b, function(tag) {
18955             if (w.indexOf(tag) > -1) {
18956                 return;
18957             }
18958             if (this.black.indexOf(tag) > -1) {
18959                 return;
18960             }
18961             this.black.push(tag);
18962             
18963         }, this);
18964         
18965         
18966         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
18967         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
18968         
18969         this.cwhite = [];
18970         this.cblack = [];
18971         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18972             if (b.indexOf(tag) > -1) {
18973                 return;
18974             }
18975             this.cwhite.push(tag);
18976             
18977         }, this);
18978         
18979         Roo.each(w, function(tag) {
18980             if (b.indexOf(tag) > -1) {
18981                 return;
18982             }
18983             if (this.cwhite.indexOf(tag) > -1) {
18984                 return;
18985             }
18986             this.cwhite.push(tag);
18987             
18988         }, this);
18989         
18990         
18991         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
18992             if (w.indexOf(tag) > -1) {
18993                 return;
18994             }
18995             this.cblack.push(tag);
18996             
18997         }, this);
18998         
18999         Roo.each(b, function(tag) {
19000             if (w.indexOf(tag) > -1) {
19001                 return;
19002             }
19003             if (this.cblack.indexOf(tag) > -1) {
19004                 return;
19005             }
19006             this.cblack.push(tag);
19007             
19008         }, this);
19009     },
19010     
19011     setStylesheets : function(stylesheets)
19012     {
19013         if(typeof(stylesheets) == 'string'){
19014             Roo.get(this.iframe.contentDocument.head).createChild({
19015                 tag : 'link',
19016                 rel : 'stylesheet',
19017                 type : 'text/css',
19018                 href : stylesheets
19019             });
19020             
19021             return;
19022         }
19023         var _this = this;
19024      
19025         Roo.each(stylesheets, function(s) {
19026             if(!s.length){
19027                 return;
19028             }
19029             
19030             Roo.get(_this.iframe.contentDocument.head).createChild({
19031                 tag : 'link',
19032                 rel : 'stylesheet',
19033                 type : 'text/css',
19034                 href : s
19035             });
19036         });
19037
19038         
19039     },
19040     
19041     removeStylesheets : function()
19042     {
19043         var _this = this;
19044         
19045         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19046             s.remove();
19047         });
19048     }
19049     
19050     // hide stuff that is not compatible
19051     /**
19052      * @event blur
19053      * @hide
19054      */
19055     /**
19056      * @event change
19057      * @hide
19058      */
19059     /**
19060      * @event focus
19061      * @hide
19062      */
19063     /**
19064      * @event specialkey
19065      * @hide
19066      */
19067     /**
19068      * @cfg {String} fieldClass @hide
19069      */
19070     /**
19071      * @cfg {String} focusClass @hide
19072      */
19073     /**
19074      * @cfg {String} autoCreate @hide
19075      */
19076     /**
19077      * @cfg {String} inputType @hide
19078      */
19079     /**
19080      * @cfg {String} invalidClass @hide
19081      */
19082     /**
19083      * @cfg {String} invalidText @hide
19084      */
19085     /**
19086      * @cfg {String} msgFx @hide
19087      */
19088     /**
19089      * @cfg {String} validateOnBlur @hide
19090      */
19091 });
19092
19093 Roo.HtmlEditorCore.white = [
19094         'area', 'br', 'img', 'input', 'hr', 'wbr',
19095         
19096        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
19097        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
19098        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
19099        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
19100        'table',   'ul',         'xmp', 
19101        
19102        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
19103       'thead',   'tr', 
19104      
19105       'dir', 'menu', 'ol', 'ul', 'dl',
19106        
19107       'embed',  'object'
19108 ];
19109
19110
19111 Roo.HtmlEditorCore.black = [
19112     //    'embed',  'object', // enable - backend responsiblity to clean thiese
19113         'applet', // 
19114         'base',   'basefont', 'bgsound', 'blink',  'body', 
19115         'frame',  'frameset', 'head',    'html',   'ilayer', 
19116         'iframe', 'layer',  'link',     'meta',    'object',   
19117         'script', 'style' ,'title',  'xml' // clean later..
19118 ];
19119 Roo.HtmlEditorCore.clean = [
19120     'script', 'style', 'title', 'xml'
19121 ];
19122 Roo.HtmlEditorCore.remove = [
19123     'font'
19124 ];
19125 // attributes..
19126
19127 Roo.HtmlEditorCore.ablack = [
19128     'on'
19129 ];
19130     
19131 Roo.HtmlEditorCore.aclean = [ 
19132     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
19133 ];
19134
19135 // protocols..
19136 Roo.HtmlEditorCore.pwhite= [
19137         'http',  'https',  'mailto'
19138 ];
19139
19140 // white listed style attributes.
19141 Roo.HtmlEditorCore.cwhite= [
19142       //  'text-align', /// default is to allow most things..
19143       
19144          
19145 //        'font-size'//??
19146 ];
19147
19148 // black listed style attributes.
19149 Roo.HtmlEditorCore.cblack= [
19150       //  'font-size' -- this can be set by the project 
19151 ];
19152
19153
19154 Roo.HtmlEditorCore.swapCodes   =[ 
19155     [    8211, "--" ], 
19156     [    8212, "--" ], 
19157     [    8216,  "'" ],  
19158     [    8217, "'" ],  
19159     [    8220, '"' ],  
19160     [    8221, '"' ],  
19161     [    8226, "*" ],  
19162     [    8230, "..." ]
19163 ]; 
19164
19165     /*
19166  * - LGPL
19167  *
19168  * HtmlEditor
19169  * 
19170  */
19171
19172 /**
19173  * @class Roo.bootstrap.HtmlEditor
19174  * @extends Roo.bootstrap.TextArea
19175  * Bootstrap HtmlEditor class
19176
19177  * @constructor
19178  * Create a new HtmlEditor
19179  * @param {Object} config The config object
19180  */
19181
19182 Roo.bootstrap.HtmlEditor = function(config){
19183     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19184     if (!this.toolbars) {
19185         this.toolbars = [];
19186     }
19187     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19188     this.addEvents({
19189             /**
19190              * @event initialize
19191              * Fires when the editor is fully initialized (including the iframe)
19192              * @param {HtmlEditor} this
19193              */
19194             initialize: true,
19195             /**
19196              * @event activate
19197              * Fires when the editor is first receives the focus. Any insertion must wait
19198              * until after this event.
19199              * @param {HtmlEditor} this
19200              */
19201             activate: true,
19202              /**
19203              * @event beforesync
19204              * Fires before the textarea is updated with content from the editor iframe. Return false
19205              * to cancel the sync.
19206              * @param {HtmlEditor} this
19207              * @param {String} html
19208              */
19209             beforesync: true,
19210              /**
19211              * @event beforepush
19212              * Fires before the iframe editor is updated with content from the textarea. Return false
19213              * to cancel the push.
19214              * @param {HtmlEditor} this
19215              * @param {String} html
19216              */
19217             beforepush: true,
19218              /**
19219              * @event sync
19220              * Fires when the textarea is updated with content from the editor iframe.
19221              * @param {HtmlEditor} this
19222              * @param {String} html
19223              */
19224             sync: true,
19225              /**
19226              * @event push
19227              * Fires when the iframe editor is updated with content from the textarea.
19228              * @param {HtmlEditor} this
19229              * @param {String} html
19230              */
19231             push: true,
19232              /**
19233              * @event editmodechange
19234              * Fires when the editor switches edit modes
19235              * @param {HtmlEditor} this
19236              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19237              */
19238             editmodechange: true,
19239             /**
19240              * @event editorevent
19241              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19242              * @param {HtmlEditor} this
19243              */
19244             editorevent: true,
19245             /**
19246              * @event firstfocus
19247              * Fires when on first focus - needed by toolbars..
19248              * @param {HtmlEditor} this
19249              */
19250             firstfocus: true,
19251             /**
19252              * @event autosave
19253              * Auto save the htmlEditor value as a file into Events
19254              * @param {HtmlEditor} this
19255              */
19256             autosave: true,
19257             /**
19258              * @event savedpreview
19259              * preview the saved version of htmlEditor
19260              * @param {HtmlEditor} this
19261              */
19262             savedpreview: true
19263         });
19264 };
19265
19266
19267 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
19268     
19269     
19270       /**
19271      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19272      */
19273     toolbars : false,
19274    
19275      /**
19276      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
19277      *                        Roo.resizable.
19278      */
19279     resizable : false,
19280      /**
19281      * @cfg {Number} height (in pixels)
19282      */   
19283     height: 300,
19284    /**
19285      * @cfg {Number} width (in pixels)
19286      */   
19287     width: false,
19288     
19289     /**
19290      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19291      * 
19292      */
19293     stylesheets: false,
19294     
19295     // id of frame..
19296     frameId: false,
19297     
19298     // private properties
19299     validationEvent : false,
19300     deferHeight: true,
19301     initialized : false,
19302     activated : false,
19303     
19304     onFocus : Roo.emptyFn,
19305     iframePad:3,
19306     hideMode:'offsets',
19307     
19308     
19309     tbContainer : false,
19310     
19311     toolbarContainer :function() {
19312         return this.wrap.select('.x-html-editor-tb',true).first();
19313     },
19314
19315     /**
19316      * Protected method that will not generally be called directly. It
19317      * is called when the editor creates its toolbar. Override this method if you need to
19318      * add custom toolbar buttons.
19319      * @param {HtmlEditor} editor
19320      */
19321     createToolbar : function(){
19322         
19323         Roo.log("create toolbars");
19324         
19325         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19326         this.toolbars[0].render(this.toolbarContainer());
19327         
19328         return;
19329         
19330 //        if (!editor.toolbars || !editor.toolbars.length) {
19331 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19332 //        }
19333 //        
19334 //        for (var i =0 ; i < editor.toolbars.length;i++) {
19335 //            editor.toolbars[i] = Roo.factory(
19336 //                    typeof(editor.toolbars[i]) == 'string' ?
19337 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
19338 //                Roo.bootstrap.HtmlEditor);
19339 //            editor.toolbars[i].init(editor);
19340 //        }
19341     },
19342
19343      
19344     // private
19345     onRender : function(ct, position)
19346     {
19347        // Roo.log("Call onRender: " + this.xtype);
19348         var _t = this;
19349         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19350       
19351         this.wrap = this.inputEl().wrap({
19352             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19353         });
19354         
19355         this.editorcore.onRender(ct, position);
19356          
19357         if (this.resizable) {
19358             this.resizeEl = new Roo.Resizable(this.wrap, {
19359                 pinned : true,
19360                 wrap: true,
19361                 dynamic : true,
19362                 minHeight : this.height,
19363                 height: this.height,
19364                 handles : this.resizable,
19365                 width: this.width,
19366                 listeners : {
19367                     resize : function(r, w, h) {
19368                         _t.onResize(w,h); // -something
19369                     }
19370                 }
19371             });
19372             
19373         }
19374         this.createToolbar(this);
19375        
19376         
19377         if(!this.width && this.resizable){
19378             this.setSize(this.wrap.getSize());
19379         }
19380         if (this.resizeEl) {
19381             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19382             // should trigger onReize..
19383         }
19384         
19385     },
19386
19387     // private
19388     onResize : function(w, h)
19389     {
19390         Roo.log('resize: ' +w + ',' + h );
19391         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19392         var ew = false;
19393         var eh = false;
19394         
19395         if(this.inputEl() ){
19396             if(typeof w == 'number'){
19397                 var aw = w - this.wrap.getFrameWidth('lr');
19398                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19399                 ew = aw;
19400             }
19401             if(typeof h == 'number'){
19402                  var tbh = -11;  // fixme it needs to tool bar size!
19403                 for (var i =0; i < this.toolbars.length;i++) {
19404                     // fixme - ask toolbars for heights?
19405                     tbh += this.toolbars[i].el.getHeight();
19406                     //if (this.toolbars[i].footer) {
19407                     //    tbh += this.toolbars[i].footer.el.getHeight();
19408                     //}
19409                 }
19410               
19411                 
19412                 
19413                 
19414                 
19415                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19416                 ah -= 5; // knock a few pixes off for look..
19417                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19418                 var eh = ah;
19419             }
19420         }
19421         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19422         this.editorcore.onResize(ew,eh);
19423         
19424     },
19425
19426     /**
19427      * Toggles the editor between standard and source edit mode.
19428      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19429      */
19430     toggleSourceEdit : function(sourceEditMode)
19431     {
19432         this.editorcore.toggleSourceEdit(sourceEditMode);
19433         
19434         if(this.editorcore.sourceEditMode){
19435             Roo.log('editor - showing textarea');
19436             
19437 //            Roo.log('in');
19438 //            Roo.log(this.syncValue());
19439             this.syncValue();
19440             this.inputEl().removeClass(['hide', 'x-hidden']);
19441             this.inputEl().dom.removeAttribute('tabIndex');
19442             this.inputEl().focus();
19443         }else{
19444             Roo.log('editor - hiding textarea');
19445 //            Roo.log('out')
19446 //            Roo.log(this.pushValue()); 
19447             this.pushValue();
19448             
19449             this.inputEl().addClass(['hide', 'x-hidden']);
19450             this.inputEl().dom.setAttribute('tabIndex', -1);
19451             //this.deferFocus();
19452         }
19453          
19454         if(this.resizable){
19455             this.setSize(this.wrap.getSize());
19456         }
19457         
19458         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19459     },
19460  
19461     // private (for BoxComponent)
19462     adjustSize : Roo.BoxComponent.prototype.adjustSize,
19463
19464     // private (for BoxComponent)
19465     getResizeEl : function(){
19466         return this.wrap;
19467     },
19468
19469     // private (for BoxComponent)
19470     getPositionEl : function(){
19471         return this.wrap;
19472     },
19473
19474     // private
19475     initEvents : function(){
19476         this.originalValue = this.getValue();
19477     },
19478
19479 //    /**
19480 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19481 //     * @method
19482 //     */
19483 //    markInvalid : Roo.emptyFn,
19484 //    /**
19485 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19486 //     * @method
19487 //     */
19488 //    clearInvalid : Roo.emptyFn,
19489
19490     setValue : function(v){
19491         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19492         this.editorcore.pushValue();
19493     },
19494
19495      
19496     // private
19497     deferFocus : function(){
19498         this.focus.defer(10, this);
19499     },
19500
19501     // doc'ed in Field
19502     focus : function(){
19503         this.editorcore.focus();
19504         
19505     },
19506       
19507
19508     // private
19509     onDestroy : function(){
19510         
19511         
19512         
19513         if(this.rendered){
19514             
19515             for (var i =0; i < this.toolbars.length;i++) {
19516                 // fixme - ask toolbars for heights?
19517                 this.toolbars[i].onDestroy();
19518             }
19519             
19520             this.wrap.dom.innerHTML = '';
19521             this.wrap.remove();
19522         }
19523     },
19524
19525     // private
19526     onFirstFocus : function(){
19527         //Roo.log("onFirstFocus");
19528         this.editorcore.onFirstFocus();
19529          for (var i =0; i < this.toolbars.length;i++) {
19530             this.toolbars[i].onFirstFocus();
19531         }
19532         
19533     },
19534     
19535     // private
19536     syncValue : function()
19537     {   
19538         this.editorcore.syncValue();
19539     },
19540     
19541     pushValue : function()
19542     {   
19543         this.editorcore.pushValue();
19544     }
19545      
19546     
19547     // hide stuff that is not compatible
19548     /**
19549      * @event blur
19550      * @hide
19551      */
19552     /**
19553      * @event change
19554      * @hide
19555      */
19556     /**
19557      * @event focus
19558      * @hide
19559      */
19560     /**
19561      * @event specialkey
19562      * @hide
19563      */
19564     /**
19565      * @cfg {String} fieldClass @hide
19566      */
19567     /**
19568      * @cfg {String} focusClass @hide
19569      */
19570     /**
19571      * @cfg {String} autoCreate @hide
19572      */
19573     /**
19574      * @cfg {String} inputType @hide
19575      */
19576     /**
19577      * @cfg {String} invalidClass @hide
19578      */
19579     /**
19580      * @cfg {String} invalidText @hide
19581      */
19582     /**
19583      * @cfg {String} msgFx @hide
19584      */
19585     /**
19586      * @cfg {String} validateOnBlur @hide
19587      */
19588 });
19589  
19590     
19591    
19592    
19593    
19594       
19595 Roo.namespace('Roo.bootstrap.htmleditor');
19596 /**
19597  * @class Roo.bootstrap.HtmlEditorToolbar1
19598  * Basic Toolbar
19599  * 
19600  * Usage:
19601  *
19602  new Roo.bootstrap.HtmlEditor({
19603     ....
19604     toolbars : [
19605         new Roo.bootstrap.HtmlEditorToolbar1({
19606             disable : { fonts: 1 , format: 1, ..., ... , ...],
19607             btns : [ .... ]
19608         })
19609     }
19610      
19611  * 
19612  * @cfg {Object} disable List of elements to disable..
19613  * @cfg {Array} btns List of additional buttons.
19614  * 
19615  * 
19616  * NEEDS Extra CSS? 
19617  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19618  */
19619  
19620 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19621 {
19622     
19623     Roo.apply(this, config);
19624     
19625     // default disabled, based on 'good practice'..
19626     this.disable = this.disable || {};
19627     Roo.applyIf(this.disable, {
19628         fontSize : true,
19629         colors : true,
19630         specialElements : true
19631     });
19632     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19633     
19634     this.editor = config.editor;
19635     this.editorcore = config.editor.editorcore;
19636     
19637     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19638     
19639     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19640     // dont call parent... till later.
19641 }
19642 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
19643      
19644     bar : true,
19645     
19646     editor : false,
19647     editorcore : false,
19648     
19649     
19650     formats : [
19651         "p" ,  
19652         "h1","h2","h3","h4","h5","h6", 
19653         "pre", "code", 
19654         "abbr", "acronym", "address", "cite", "samp", "var",
19655         'div','span'
19656     ],
19657     
19658     onRender : function(ct, position)
19659     {
19660        // Roo.log("Call onRender: " + this.xtype);
19661         
19662        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19663        Roo.log(this.el);
19664        this.el.dom.style.marginBottom = '0';
19665        var _this = this;
19666        var editorcore = this.editorcore;
19667        var editor= this.editor;
19668        
19669        var children = [];
19670        var btn = function(id,cmd , toggle, handler){
19671        
19672             var  event = toggle ? 'toggle' : 'click';
19673        
19674             var a = {
19675                 size : 'sm',
19676                 xtype: 'Button',
19677                 xns: Roo.bootstrap,
19678                 glyphicon : id,
19679                 cmd : id || cmd,
19680                 enableToggle:toggle !== false,
19681                 //html : 'submit'
19682                 pressed : toggle ? false : null,
19683                 listeners : {}
19684             }
19685             a.listeners[toggle ? 'toggle' : 'click'] = function() {
19686                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
19687             }
19688             children.push(a);
19689             return a;
19690        }
19691         
19692         var style = {
19693                 xtype: 'Button',
19694                 size : 'sm',
19695                 xns: Roo.bootstrap,
19696                 glyphicon : 'font',
19697                 //html : 'submit'
19698                 menu : {
19699                     xtype: 'Menu',
19700                     xns: Roo.bootstrap,
19701                     items:  []
19702                 }
19703         };
19704         Roo.each(this.formats, function(f) {
19705             style.menu.items.push({
19706                 xtype :'MenuItem',
19707                 xns: Roo.bootstrap,
19708                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19709                 tagname : f,
19710                 listeners : {
19711                     click : function()
19712                     {
19713                         editorcore.insertTag(this.tagname);
19714                         editor.focus();
19715                     }
19716                 }
19717                 
19718             });
19719         });
19720          children.push(style);   
19721             
19722             
19723         btn('bold',false,true);
19724         btn('italic',false,true);
19725         btn('align-left', 'justifyleft',true);
19726         btn('align-center', 'justifycenter',true);
19727         btn('align-right' , 'justifyright',true);
19728         btn('link', false, false, function(btn) {
19729             //Roo.log("create link?");
19730             var url = prompt(this.createLinkText, this.defaultLinkValue);
19731             if(url && url != 'http:/'+'/'){
19732                 this.editorcore.relayCmd('createlink', url);
19733             }
19734         }),
19735         btn('list','insertunorderedlist',true);
19736         btn('pencil', false,true, function(btn){
19737                 Roo.log(this);
19738                 
19739                 this.toggleSourceEdit(btn.pressed);
19740         });
19741         /*
19742         var cog = {
19743                 xtype: 'Button',
19744                 size : 'sm',
19745                 xns: Roo.bootstrap,
19746                 glyphicon : 'cog',
19747                 //html : 'submit'
19748                 menu : {
19749                     xtype: 'Menu',
19750                     xns: Roo.bootstrap,
19751                     items:  []
19752                 }
19753         };
19754         
19755         cog.menu.items.push({
19756             xtype :'MenuItem',
19757             xns: Roo.bootstrap,
19758             html : Clean styles,
19759             tagname : f,
19760             listeners : {
19761                 click : function()
19762                 {
19763                     editorcore.insertTag(this.tagname);
19764                     editor.focus();
19765                 }
19766             }
19767             
19768         });
19769        */
19770         
19771          
19772        this.xtype = 'NavSimplebar';
19773         
19774         for(var i=0;i< children.length;i++) {
19775             
19776             this.buttons.add(this.addxtypeChild(children[i]));
19777             
19778         }
19779         
19780         editor.on('editorevent', this.updateToolbar, this);
19781     },
19782     onBtnClick : function(id)
19783     {
19784        this.editorcore.relayCmd(id);
19785        this.editorcore.focus();
19786     },
19787     
19788     /**
19789      * Protected method that will not generally be called directly. It triggers
19790      * a toolbar update by reading the markup state of the current selection in the editor.
19791      */
19792     updateToolbar: function(){
19793
19794         if(!this.editorcore.activated){
19795             this.editor.onFirstFocus(); // is this neeed?
19796             return;
19797         }
19798
19799         var btns = this.buttons; 
19800         var doc = this.editorcore.doc;
19801         btns.get('bold').setActive(doc.queryCommandState('bold'));
19802         btns.get('italic').setActive(doc.queryCommandState('italic'));
19803         //btns.get('underline').setActive(doc.queryCommandState('underline'));
19804         
19805         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19806         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19807         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19808         
19809         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19810         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19811          /*
19812         
19813         var ans = this.editorcore.getAllAncestors();
19814         if (this.formatCombo) {
19815             
19816             
19817             var store = this.formatCombo.store;
19818             this.formatCombo.setValue("");
19819             for (var i =0; i < ans.length;i++) {
19820                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19821                     // select it..
19822                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19823                     break;
19824                 }
19825             }
19826         }
19827         
19828         
19829         
19830         // hides menus... - so this cant be on a menu...
19831         Roo.bootstrap.MenuMgr.hideAll();
19832         */
19833         Roo.bootstrap.MenuMgr.hideAll();
19834         //this.editorsyncValue();
19835     },
19836     onFirstFocus: function() {
19837         this.buttons.each(function(item){
19838            item.enable();
19839         });
19840     },
19841     toggleSourceEdit : function(sourceEditMode){
19842         
19843           
19844         if(sourceEditMode){
19845             Roo.log("disabling buttons");
19846            this.buttons.each( function(item){
19847                 if(item.cmd != 'pencil'){
19848                     item.disable();
19849                 }
19850             });
19851           
19852         }else{
19853             Roo.log("enabling buttons");
19854             if(this.editorcore.initialized){
19855                 this.buttons.each( function(item){
19856                     item.enable();
19857                 });
19858             }
19859             
19860         }
19861         Roo.log("calling toggole on editor");
19862         // tell the editor that it's been pressed..
19863         this.editor.toggleSourceEdit(sourceEditMode);
19864        
19865     }
19866 });
19867
19868
19869
19870
19871
19872 /**
19873  * @class Roo.bootstrap.Table.AbstractSelectionModel
19874  * @extends Roo.util.Observable
19875  * Abstract base class for grid SelectionModels.  It provides the interface that should be
19876  * implemented by descendant classes.  This class should not be directly instantiated.
19877  * @constructor
19878  */
19879 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19880     this.locked = false;
19881     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19882 };
19883
19884
19885 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
19886     /** @ignore Called by the grid automatically. Do not call directly. */
19887     init : function(grid){
19888         this.grid = grid;
19889         this.initEvents();
19890     },
19891
19892     /**
19893      * Locks the selections.
19894      */
19895     lock : function(){
19896         this.locked = true;
19897     },
19898
19899     /**
19900      * Unlocks the selections.
19901      */
19902     unlock : function(){
19903         this.locked = false;
19904     },
19905
19906     /**
19907      * Returns true if the selections are locked.
19908      * @return {Boolean}
19909      */
19910     isLocked : function(){
19911         return this.locked;
19912     }
19913 });
19914 /**
19915  * @extends Roo.bootstrap.Table.AbstractSelectionModel
19916  * @class Roo.bootstrap.Table.RowSelectionModel
19917  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19918  * It supports multiple selections and keyboard selection/navigation. 
19919  * @constructor
19920  * @param {Object} config
19921  */
19922
19923 Roo.bootstrap.Table.RowSelectionModel = function(config){
19924     Roo.apply(this, config);
19925     this.selections = new Roo.util.MixedCollection(false, function(o){
19926         return o.id;
19927     });
19928
19929     this.last = false;
19930     this.lastActive = false;
19931
19932     this.addEvents({
19933         /**
19934              * @event selectionchange
19935              * Fires when the selection changes
19936              * @param {SelectionModel} this
19937              */
19938             "selectionchange" : true,
19939         /**
19940              * @event afterselectionchange
19941              * Fires after the selection changes (eg. by key press or clicking)
19942              * @param {SelectionModel} this
19943              */
19944             "afterselectionchange" : true,
19945         /**
19946              * @event beforerowselect
19947              * Fires when a row is selected being selected, return false to cancel.
19948              * @param {SelectionModel} this
19949              * @param {Number} rowIndex The selected index
19950              * @param {Boolean} keepExisting False if other selections will be cleared
19951              */
19952             "beforerowselect" : true,
19953         /**
19954              * @event rowselect
19955              * Fires when a row is selected.
19956              * @param {SelectionModel} this
19957              * @param {Number} rowIndex The selected index
19958              * @param {Roo.data.Record} r The record
19959              */
19960             "rowselect" : true,
19961         /**
19962              * @event rowdeselect
19963              * Fires when a row is deselected.
19964              * @param {SelectionModel} this
19965              * @param {Number} rowIndex The selected index
19966              */
19967         "rowdeselect" : true
19968     });
19969     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19970     this.locked = false;
19971 };
19972
19973 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
19974     /**
19975      * @cfg {Boolean} singleSelect
19976      * True to allow selection of only one row at a time (defaults to false)
19977      */
19978     singleSelect : false,
19979
19980     // private
19981     initEvents : function(){
19982
19983         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
19984             this.grid.on("mousedown", this.handleMouseDown, this);
19985         }else{ // allow click to work like normal
19986             this.grid.on("rowclick", this.handleDragableRowClick, this);
19987         }
19988
19989         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
19990             "up" : function(e){
19991                 if(!e.shiftKey){
19992                     this.selectPrevious(e.shiftKey);
19993                 }else if(this.last !== false && this.lastActive !== false){
19994                     var last = this.last;
19995                     this.selectRange(this.last,  this.lastActive-1);
19996                     this.grid.getView().focusRow(this.lastActive);
19997                     if(last !== false){
19998                         this.last = last;
19999                     }
20000                 }else{
20001                     this.selectFirstRow();
20002                 }
20003                 this.fireEvent("afterselectionchange", this);
20004             },
20005             "down" : function(e){
20006                 if(!e.shiftKey){
20007                     this.selectNext(e.shiftKey);
20008                 }else if(this.last !== false && this.lastActive !== false){
20009                     var last = this.last;
20010                     this.selectRange(this.last,  this.lastActive+1);
20011                     this.grid.getView().focusRow(this.lastActive);
20012                     if(last !== false){
20013                         this.last = last;
20014                     }
20015                 }else{
20016                     this.selectFirstRow();
20017                 }
20018                 this.fireEvent("afterselectionchange", this);
20019             },
20020             scope: this
20021         });
20022
20023         var view = this.grid.view;
20024         view.on("refresh", this.onRefresh, this);
20025         view.on("rowupdated", this.onRowUpdated, this);
20026         view.on("rowremoved", this.onRemove, this);
20027     },
20028
20029     // private
20030     onRefresh : function(){
20031         var ds = this.grid.dataSource, i, v = this.grid.view;
20032         var s = this.selections;
20033         s.each(function(r){
20034             if((i = ds.indexOfId(r.id)) != -1){
20035                 v.onRowSelect(i);
20036             }else{
20037                 s.remove(r);
20038             }
20039         });
20040     },
20041
20042     // private
20043     onRemove : function(v, index, r){
20044         this.selections.remove(r);
20045     },
20046
20047     // private
20048     onRowUpdated : function(v, index, r){
20049         if(this.isSelected(r)){
20050             v.onRowSelect(index);
20051         }
20052     },
20053
20054     /**
20055      * Select records.
20056      * @param {Array} records The records to select
20057      * @param {Boolean} keepExisting (optional) True to keep existing selections
20058      */
20059     selectRecords : function(records, keepExisting){
20060         if(!keepExisting){
20061             this.clearSelections();
20062         }
20063         var ds = this.grid.dataSource;
20064         for(var i = 0, len = records.length; i < len; i++){
20065             this.selectRow(ds.indexOf(records[i]), true);
20066         }
20067     },
20068
20069     /**
20070      * Gets the number of selected rows.
20071      * @return {Number}
20072      */
20073     getCount : function(){
20074         return this.selections.length;
20075     },
20076
20077     /**
20078      * Selects the first row in the grid.
20079      */
20080     selectFirstRow : function(){
20081         this.selectRow(0);
20082     },
20083
20084     /**
20085      * Select the last row.
20086      * @param {Boolean} keepExisting (optional) True to keep existing selections
20087      */
20088     selectLastRow : function(keepExisting){
20089         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20090     },
20091
20092     /**
20093      * Selects the row immediately following the last selected row.
20094      * @param {Boolean} keepExisting (optional) True to keep existing selections
20095      */
20096     selectNext : function(keepExisting){
20097         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20098             this.selectRow(this.last+1, keepExisting);
20099             this.grid.getView().focusRow(this.last);
20100         }
20101     },
20102
20103     /**
20104      * Selects the row that precedes the last selected row.
20105      * @param {Boolean} keepExisting (optional) True to keep existing selections
20106      */
20107     selectPrevious : function(keepExisting){
20108         if(this.last){
20109             this.selectRow(this.last-1, keepExisting);
20110             this.grid.getView().focusRow(this.last);
20111         }
20112     },
20113
20114     /**
20115      * Returns the selected records
20116      * @return {Array} Array of selected records
20117      */
20118     getSelections : function(){
20119         return [].concat(this.selections.items);
20120     },
20121
20122     /**
20123      * Returns the first selected record.
20124      * @return {Record}
20125      */
20126     getSelected : function(){
20127         return this.selections.itemAt(0);
20128     },
20129
20130
20131     /**
20132      * Clears all selections.
20133      */
20134     clearSelections : function(fast){
20135         if(this.locked) return;
20136         if(fast !== true){
20137             var ds = this.grid.dataSource;
20138             var s = this.selections;
20139             s.each(function(r){
20140                 this.deselectRow(ds.indexOfId(r.id));
20141             }, this);
20142             s.clear();
20143         }else{
20144             this.selections.clear();
20145         }
20146         this.last = false;
20147     },
20148
20149
20150     /**
20151      * Selects all rows.
20152      */
20153     selectAll : function(){
20154         if(this.locked) return;
20155         this.selections.clear();
20156         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20157             this.selectRow(i, true);
20158         }
20159     },
20160
20161     /**
20162      * Returns True if there is a selection.
20163      * @return {Boolean}
20164      */
20165     hasSelection : function(){
20166         return this.selections.length > 0;
20167     },
20168
20169     /**
20170      * Returns True if the specified row is selected.
20171      * @param {Number/Record} record The record or index of the record to check
20172      * @return {Boolean}
20173      */
20174     isSelected : function(index){
20175         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20176         return (r && this.selections.key(r.id) ? true : false);
20177     },
20178
20179     /**
20180      * Returns True if the specified record id is selected.
20181      * @param {String} id The id of record to check
20182      * @return {Boolean}
20183      */
20184     isIdSelected : function(id){
20185         return (this.selections.key(id) ? true : false);
20186     },
20187
20188     // private
20189     handleMouseDown : function(e, t){
20190         var view = this.grid.getView(), rowIndex;
20191         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20192             return;
20193         };
20194         if(e.shiftKey && this.last !== false){
20195             var last = this.last;
20196             this.selectRange(last, rowIndex, e.ctrlKey);
20197             this.last = last; // reset the last
20198             view.focusRow(rowIndex);
20199         }else{
20200             var isSelected = this.isSelected(rowIndex);
20201             if(e.button !== 0 && isSelected){
20202                 view.focusRow(rowIndex);
20203             }else if(e.ctrlKey && isSelected){
20204                 this.deselectRow(rowIndex);
20205             }else if(!isSelected){
20206                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20207                 view.focusRow(rowIndex);
20208             }
20209         }
20210         this.fireEvent("afterselectionchange", this);
20211     },
20212     // private
20213     handleDragableRowClick :  function(grid, rowIndex, e) 
20214     {
20215         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20216             this.selectRow(rowIndex, false);
20217             grid.view.focusRow(rowIndex);
20218              this.fireEvent("afterselectionchange", this);
20219         }
20220     },
20221     
20222     /**
20223      * Selects multiple rows.
20224      * @param {Array} rows Array of the indexes of the row to select
20225      * @param {Boolean} keepExisting (optional) True to keep existing selections
20226      */
20227     selectRows : function(rows, keepExisting){
20228         if(!keepExisting){
20229             this.clearSelections();
20230         }
20231         for(var i = 0, len = rows.length; i < len; i++){
20232             this.selectRow(rows[i], true);
20233         }
20234     },
20235
20236     /**
20237      * Selects a range of rows. All rows in between startRow and endRow are also selected.
20238      * @param {Number} startRow The index of the first row in the range
20239      * @param {Number} endRow The index of the last row in the range
20240      * @param {Boolean} keepExisting (optional) True to retain existing selections
20241      */
20242     selectRange : function(startRow, endRow, keepExisting){
20243         if(this.locked) return;
20244         if(!keepExisting){
20245             this.clearSelections();
20246         }
20247         if(startRow <= endRow){
20248             for(var i = startRow; i <= endRow; i++){
20249                 this.selectRow(i, true);
20250             }
20251         }else{
20252             for(var i = startRow; i >= endRow; i--){
20253                 this.selectRow(i, true);
20254             }
20255         }
20256     },
20257
20258     /**
20259      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20260      * @param {Number} startRow The index of the first row in the range
20261      * @param {Number} endRow The index of the last row in the range
20262      */
20263     deselectRange : function(startRow, endRow, preventViewNotify){
20264         if(this.locked) return;
20265         for(var i = startRow; i <= endRow; i++){
20266             this.deselectRow(i, preventViewNotify);
20267         }
20268     },
20269
20270     /**
20271      * Selects a row.
20272      * @param {Number} row The index of the row to select
20273      * @param {Boolean} keepExisting (optional) True to keep existing selections
20274      */
20275     selectRow : function(index, keepExisting, preventViewNotify){
20276         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20277         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20278             if(!keepExisting || this.singleSelect){
20279                 this.clearSelections();
20280             }
20281             var r = this.grid.dataSource.getAt(index);
20282             this.selections.add(r);
20283             this.last = this.lastActive = index;
20284             if(!preventViewNotify){
20285                 this.grid.getView().onRowSelect(index);
20286             }
20287             this.fireEvent("rowselect", this, index, r);
20288             this.fireEvent("selectionchange", this);
20289         }
20290     },
20291
20292     /**
20293      * Deselects a row.
20294      * @param {Number} row The index of the row to deselect
20295      */
20296     deselectRow : function(index, preventViewNotify){
20297         if(this.locked) return;
20298         if(this.last == index){
20299             this.last = false;
20300         }
20301         if(this.lastActive == index){
20302             this.lastActive = false;
20303         }
20304         var r = this.grid.dataSource.getAt(index);
20305         this.selections.remove(r);
20306         if(!preventViewNotify){
20307             this.grid.getView().onRowDeselect(index);
20308         }
20309         this.fireEvent("rowdeselect", this, index);
20310         this.fireEvent("selectionchange", this);
20311     },
20312
20313     // private
20314     restoreLast : function(){
20315         if(this._last){
20316             this.last = this._last;
20317         }
20318     },
20319
20320     // private
20321     acceptsNav : function(row, col, cm){
20322         return !cm.isHidden(col) && cm.isCellEditable(col, row);
20323     },
20324
20325     // private
20326     onEditorKey : function(field, e){
20327         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20328         if(k == e.TAB){
20329             e.stopEvent();
20330             ed.completeEdit();
20331             if(e.shiftKey){
20332                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20333             }else{
20334                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20335             }
20336         }else if(k == e.ENTER && !e.ctrlKey){
20337             e.stopEvent();
20338             ed.completeEdit();
20339             if(e.shiftKey){
20340                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20341             }else{
20342                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20343             }
20344         }else if(k == e.ESC){
20345             ed.cancelEdit();
20346         }
20347         if(newCell){
20348             g.startEditing(newCell[0], newCell[1]);
20349         }
20350     }
20351 });/*
20352  * Based on:
20353  * Ext JS Library 1.1.1
20354  * Copyright(c) 2006-2007, Ext JS, LLC.
20355  *
20356  * Originally Released Under LGPL - original licence link has changed is not relivant.
20357  *
20358  * Fork - LGPL
20359  * <script type="text/javascript">
20360  */
20361  
20362 /**
20363  * @class Roo.bootstrap.PagingToolbar
20364  * @extends Roo.Row
20365  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20366  * @constructor
20367  * Create a new PagingToolbar
20368  * @param {Object} config The config object
20369  */
20370 Roo.bootstrap.PagingToolbar = function(config)
20371 {
20372     // old args format still supported... - xtype is prefered..
20373         // created from xtype...
20374     var ds = config.dataSource;
20375     this.toolbarItems = [];
20376     if (config.items) {
20377         this.toolbarItems = config.items;
20378 //        config.items = [];
20379     }
20380     
20381     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20382     this.ds = ds;
20383     this.cursor = 0;
20384     if (ds) { 
20385         this.bind(ds);
20386     }
20387     
20388     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20389     
20390 };
20391
20392 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20393     /**
20394      * @cfg {Roo.data.Store} dataSource
20395      * The underlying data store providing the paged data
20396      */
20397     /**
20398      * @cfg {String/HTMLElement/Element} container
20399      * container The id or element that will contain the toolbar
20400      */
20401     /**
20402      * @cfg {Boolean} displayInfo
20403      * True to display the displayMsg (defaults to false)
20404      */
20405     /**
20406      * @cfg {Number} pageSize
20407      * The number of records to display per page (defaults to 20)
20408      */
20409     pageSize: 20,
20410     /**
20411      * @cfg {String} displayMsg
20412      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20413      */
20414     displayMsg : 'Displaying {0} - {1} of {2}',
20415     /**
20416      * @cfg {String} emptyMsg
20417      * The message to display when no records are found (defaults to "No data to display")
20418      */
20419     emptyMsg : 'No data to display',
20420     /**
20421      * Customizable piece of the default paging text (defaults to "Page")
20422      * @type String
20423      */
20424     beforePageText : "Page",
20425     /**
20426      * Customizable piece of the default paging text (defaults to "of %0")
20427      * @type String
20428      */
20429     afterPageText : "of {0}",
20430     /**
20431      * Customizable piece of the default paging text (defaults to "First Page")
20432      * @type String
20433      */
20434     firstText : "First Page",
20435     /**
20436      * Customizable piece of the default paging text (defaults to "Previous Page")
20437      * @type String
20438      */
20439     prevText : "Previous Page",
20440     /**
20441      * Customizable piece of the default paging text (defaults to "Next Page")
20442      * @type String
20443      */
20444     nextText : "Next Page",
20445     /**
20446      * Customizable piece of the default paging text (defaults to "Last Page")
20447      * @type String
20448      */
20449     lastText : "Last Page",
20450     /**
20451      * Customizable piece of the default paging text (defaults to "Refresh")
20452      * @type String
20453      */
20454     refreshText : "Refresh",
20455
20456     buttons : false,
20457     // private
20458     onRender : function(ct, position) 
20459     {
20460         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20461         this.navgroup.parentId = this.id;
20462         this.navgroup.onRender(this.el, null);
20463         // add the buttons to the navgroup
20464         
20465         if(this.displayInfo){
20466             Roo.log(this.el.select('ul.navbar-nav',true).first());
20467             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20468             this.displayEl = this.el.select('.x-paging-info', true).first();
20469 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20470 //            this.displayEl = navel.el.select('span',true).first();
20471         }
20472         
20473         var _this = this;
20474         
20475         if(this.buttons){
20476             Roo.each(_this.buttons, function(e){
20477                Roo.factory(e).onRender(_this.el, null);
20478             });
20479         }
20480             
20481         Roo.each(_this.toolbarItems, function(e) {
20482             _this.navgroup.addItem(e);
20483         });
20484         
20485         
20486         this.first = this.navgroup.addItem({
20487             tooltip: this.firstText,
20488             cls: "prev",
20489             icon : 'fa fa-backward',
20490             disabled: true,
20491             preventDefault: true,
20492             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20493         });
20494         
20495         this.prev =  this.navgroup.addItem({
20496             tooltip: this.prevText,
20497             cls: "prev",
20498             icon : 'fa fa-step-backward',
20499             disabled: true,
20500             preventDefault: true,
20501             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
20502         });
20503     //this.addSeparator();
20504         
20505         
20506         var field = this.navgroup.addItem( {
20507             tagtype : 'span',
20508             cls : 'x-paging-position',
20509             
20510             html : this.beforePageText  +
20511                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20512                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
20513          } ); //?? escaped?
20514         
20515         this.field = field.el.select('input', true).first();
20516         this.field.on("keydown", this.onPagingKeydown, this);
20517         this.field.on("focus", function(){this.dom.select();});
20518     
20519     
20520         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
20521         //this.field.setHeight(18);
20522         //this.addSeparator();
20523         this.next = this.navgroup.addItem({
20524             tooltip: this.nextText,
20525             cls: "next",
20526             html : ' <i class="fa fa-step-forward">',
20527             disabled: true,
20528             preventDefault: true,
20529             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
20530         });
20531         this.last = this.navgroup.addItem({
20532             tooltip: this.lastText,
20533             icon : 'fa fa-forward',
20534             cls: "next",
20535             disabled: true,
20536             preventDefault: true,
20537             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
20538         });
20539     //this.addSeparator();
20540         this.loading = this.navgroup.addItem({
20541             tooltip: this.refreshText,
20542             icon: 'fa fa-refresh',
20543             preventDefault: true,
20544             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20545         });
20546
20547     },
20548
20549     // private
20550     updateInfo : function(){
20551         if(this.displayEl){
20552             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20553             var msg = count == 0 ?
20554                 this.emptyMsg :
20555                 String.format(
20556                     this.displayMsg,
20557                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
20558                 );
20559             this.displayEl.update(msg);
20560         }
20561     },
20562
20563     // private
20564     onLoad : function(ds, r, o){
20565        this.cursor = o.params ? o.params.start : 0;
20566        var d = this.getPageData(),
20567             ap = d.activePage,
20568             ps = d.pages;
20569         
20570        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20571        this.field.dom.value = ap;
20572        this.first.setDisabled(ap == 1);
20573        this.prev.setDisabled(ap == 1);
20574        this.next.setDisabled(ap == ps);
20575        this.last.setDisabled(ap == ps);
20576        this.loading.enable();
20577        this.updateInfo();
20578     },
20579
20580     // private
20581     getPageData : function(){
20582         var total = this.ds.getTotalCount();
20583         return {
20584             total : total,
20585             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20586             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20587         };
20588     },
20589
20590     // private
20591     onLoadError : function(){
20592         this.loading.enable();
20593     },
20594
20595     // private
20596     onPagingKeydown : function(e){
20597         var k = e.getKey();
20598         var d = this.getPageData();
20599         if(k == e.RETURN){
20600             var v = this.field.dom.value, pageNum;
20601             if(!v || isNaN(pageNum = parseInt(v, 10))){
20602                 this.field.dom.value = d.activePage;
20603                 return;
20604             }
20605             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20606             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20607             e.stopEvent();
20608         }
20609         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))
20610         {
20611           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20612           this.field.dom.value = pageNum;
20613           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20614           e.stopEvent();
20615         }
20616         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20617         {
20618           var v = this.field.dom.value, pageNum; 
20619           var increment = (e.shiftKey) ? 10 : 1;
20620           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20621             increment *= -1;
20622           if(!v || isNaN(pageNum = parseInt(v, 10))) {
20623             this.field.dom.value = d.activePage;
20624             return;
20625           }
20626           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20627           {
20628             this.field.dom.value = parseInt(v, 10) + increment;
20629             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20630             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20631           }
20632           e.stopEvent();
20633         }
20634     },
20635
20636     // private
20637     beforeLoad : function(){
20638         if(this.loading){
20639             this.loading.disable();
20640         }
20641     },
20642
20643     // private
20644     onClick : function(which){
20645         
20646         var ds = this.ds;
20647         if (!ds) {
20648             return;
20649         }
20650         
20651         switch(which){
20652             case "first":
20653                 ds.load({params:{start: 0, limit: this.pageSize}});
20654             break;
20655             case "prev":
20656                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20657             break;
20658             case "next":
20659                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20660             break;
20661             case "last":
20662                 var total = ds.getTotalCount();
20663                 var extra = total % this.pageSize;
20664                 var lastStart = extra ? (total - extra) : total-this.pageSize;
20665                 ds.load({params:{start: lastStart, limit: this.pageSize}});
20666             break;
20667             case "refresh":
20668                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20669             break;
20670         }
20671     },
20672
20673     /**
20674      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20675      * @param {Roo.data.Store} store The data store to unbind
20676      */
20677     unbind : function(ds){
20678         ds.un("beforeload", this.beforeLoad, this);
20679         ds.un("load", this.onLoad, this);
20680         ds.un("loadexception", this.onLoadError, this);
20681         ds.un("remove", this.updateInfo, this);
20682         ds.un("add", this.updateInfo, this);
20683         this.ds = undefined;
20684     },
20685
20686     /**
20687      * Binds the paging toolbar to the specified {@link Roo.data.Store}
20688      * @param {Roo.data.Store} store The data store to bind
20689      */
20690     bind : function(ds){
20691         ds.on("beforeload", this.beforeLoad, this);
20692         ds.on("load", this.onLoad, this);
20693         ds.on("loadexception", this.onLoadError, this);
20694         ds.on("remove", this.updateInfo, this);
20695         ds.on("add", this.updateInfo, this);
20696         this.ds = ds;
20697     }
20698 });/*
20699  * - LGPL
20700  *
20701  * element
20702  * 
20703  */
20704
20705 /**
20706  * @class Roo.bootstrap.MessageBar
20707  * @extends Roo.bootstrap.Component
20708  * Bootstrap MessageBar class
20709  * @cfg {String} html contents of the MessageBar
20710  * @cfg {String} weight (info | success | warning | danger) default info
20711  * @cfg {String} beforeClass insert the bar before the given class
20712  * @cfg {Boolean} closable (true | false) default false
20713  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20714  * 
20715  * @constructor
20716  * Create a new Element
20717  * @param {Object} config The config object
20718  */
20719
20720 Roo.bootstrap.MessageBar = function(config){
20721     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20722 };
20723
20724 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
20725     
20726     html: '',
20727     weight: 'info',
20728     closable: false,
20729     fixed: false,
20730     beforeClass: 'bootstrap-sticky-wrap',
20731     
20732     getAutoCreate : function(){
20733         
20734         var cfg = {
20735             tag: 'div',
20736             cls: 'alert alert-dismissable alert-' + this.weight,
20737             cn: [
20738                 {
20739                     tag: 'span',
20740                     cls: 'message',
20741                     html: this.html || ''
20742                 }
20743             ]
20744         }
20745         
20746         if(this.fixed){
20747             cfg.cls += ' alert-messages-fixed';
20748         }
20749         
20750         if(this.closable){
20751             cfg.cn.push({
20752                 tag: 'button',
20753                 cls: 'close',
20754                 html: 'x'
20755             });
20756         }
20757         
20758         return cfg;
20759     },
20760     
20761     onRender : function(ct, position)
20762     {
20763         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20764         
20765         if(!this.el){
20766             var cfg = Roo.apply({},  this.getAutoCreate());
20767             cfg.id = Roo.id();
20768             
20769             if (this.cls) {
20770                 cfg.cls += ' ' + this.cls;
20771             }
20772             if (this.style) {
20773                 cfg.style = this.style;
20774             }
20775             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20776             
20777             this.el.setVisibilityMode(Roo.Element.DISPLAY);
20778         }
20779         
20780         this.el.select('>button.close').on('click', this.hide, this);
20781         
20782     },
20783     
20784     show : function()
20785     {
20786         if (!this.rendered) {
20787             this.render();
20788         }
20789         
20790         this.el.show();
20791         
20792         this.fireEvent('show', this);
20793         
20794     },
20795     
20796     hide : function()
20797     {
20798         if (!this.rendered) {
20799             this.render();
20800         }
20801         
20802         this.el.hide();
20803         
20804         this.fireEvent('hide', this);
20805     },
20806     
20807     update : function()
20808     {
20809 //        var e = this.el.dom.firstChild;
20810 //        
20811 //        if(this.closable){
20812 //            e = e.nextSibling;
20813 //        }
20814 //        
20815 //        e.data = this.html || '';
20816
20817         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20818     }
20819    
20820 });
20821
20822  
20823
20824      /*
20825  * - LGPL
20826  *
20827  * Graph
20828  * 
20829  */
20830
20831
20832 /**
20833  * @class Roo.bootstrap.Graph
20834  * @extends Roo.bootstrap.Component
20835  * Bootstrap Graph class
20836 > Prameters
20837  -sm {number} sm 4
20838  -md {number} md 5
20839  @cfg {String} graphtype  bar | vbar | pie
20840  @cfg {number} g_x coodinator | centre x (pie)
20841  @cfg {number} g_y coodinator | centre y (pie)
20842  @cfg {number} g_r radius (pie)
20843  @cfg {number} g_height height of the chart (respected by all elements in the set)
20844  @cfg {number} g_width width of the chart (respected by all elements in the set)
20845  @cfg {Object} title The title of the chart
20846     
20847  -{Array}  values
20848  -opts (object) options for the chart 
20849      o {
20850      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20851      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20852      o vgutter (number)
20853      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.
20854      o stacked (boolean) whether or not to tread values as in a stacked bar chart
20855      o to
20856      o stretch (boolean)
20857      o }
20858  -opts (object) options for the pie
20859      o{
20860      o cut
20861      o startAngle (number)
20862      o endAngle (number)
20863      } 
20864  *
20865  * @constructor
20866  * Create a new Input
20867  * @param {Object} config The config object
20868  */
20869
20870 Roo.bootstrap.Graph = function(config){
20871     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20872     
20873     this.addEvents({
20874         // img events
20875         /**
20876          * @event click
20877          * The img click event for the img.
20878          * @param {Roo.EventObject} e
20879          */
20880         "click" : true
20881     });
20882 };
20883
20884 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
20885     
20886     sm: 4,
20887     md: 5,
20888     graphtype: 'bar',
20889     g_height: 250,
20890     g_width: 400,
20891     g_x: 50,
20892     g_y: 50,
20893     g_r: 30,
20894     opts:{
20895         //g_colors: this.colors,
20896         g_type: 'soft',
20897         g_gutter: '20%'
20898
20899     },
20900     title : false,
20901
20902     getAutoCreate : function(){
20903         
20904         var cfg = {
20905             tag: 'div',
20906             html : null
20907         }
20908         
20909         
20910         return  cfg;
20911     },
20912
20913     onRender : function(ct,position){
20914         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20915         this.raphael = Raphael(this.el.dom);
20916         
20917                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20918                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20919                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20920                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20921                 /*
20922                 r.text(160, 10, "Single Series Chart").attr(txtattr);
20923                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20924                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20925                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20926                 
20927                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20928                 r.barchart(330, 10, 300, 220, data1);
20929                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20930                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20931                 */
20932                 
20933                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20934                 // r.barchart(30, 30, 560, 250,  xdata, {
20935                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20936                 //     axis : "0 0 1 1",
20937                 //     axisxlabels :  xdata
20938                 //     //yvalues : cols,
20939                    
20940                 // });
20941 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20942 //        
20943 //        this.load(null,xdata,{
20944 //                axis : "0 0 1 1",
20945 //                axisxlabels :  xdata
20946 //                });
20947
20948     },
20949
20950     load : function(graphtype,xdata,opts){
20951         this.raphael.clear();
20952         if(!graphtype) {
20953             graphtype = this.graphtype;
20954         }
20955         if(!opts){
20956             opts = this.opts;
20957         }
20958         var r = this.raphael,
20959             fin = function () {
20960                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20961             },
20962             fout = function () {
20963                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20964             },
20965             pfin = function() {
20966                 this.sector.stop();
20967                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20968
20969                 if (this.label) {
20970                     this.label[0].stop();
20971                     this.label[0].attr({ r: 7.5 });
20972                     this.label[1].attr({ "font-weight": 800 });
20973                 }
20974             },
20975             pfout = function() {
20976                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20977
20978                 if (this.label) {
20979                     this.label[0].animate({ r: 5 }, 500, "bounce");
20980                     this.label[1].attr({ "font-weight": 400 });
20981                 }
20982             };
20983
20984         switch(graphtype){
20985             case 'bar':
20986                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20987                 break;
20988             case 'hbar':
20989                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
20990                 break;
20991             case 'pie':
20992 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
20993 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
20994 //            
20995                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
20996                 
20997                 break;
20998
20999         }
21000         
21001         if(this.title){
21002             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21003         }
21004         
21005     },
21006     
21007     setTitle: function(o)
21008     {
21009         this.title = o;
21010     },
21011     
21012     initEvents: function() {
21013         
21014         if(!this.href){
21015             this.el.on('click', this.onClick, this);
21016         }
21017     },
21018     
21019     onClick : function(e)
21020     {
21021         Roo.log('img onclick');
21022         this.fireEvent('click', this, e);
21023     }
21024    
21025 });
21026
21027  
21028 /*
21029  * - LGPL
21030  *
21031  * numberBox
21032  * 
21033  */
21034 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21035
21036 /**
21037  * @class Roo.bootstrap.dash.NumberBox
21038  * @extends Roo.bootstrap.Component
21039  * Bootstrap NumberBox class
21040  * @cfg {String} headline Box headline
21041  * @cfg {String} content Box content
21042  * @cfg {String} icon Box icon
21043  * @cfg {String} footer Footer text
21044  * @cfg {String} fhref Footer href
21045  * 
21046  * @constructor
21047  * Create a new NumberBox
21048  * @param {Object} config The config object
21049  */
21050
21051
21052 Roo.bootstrap.dash.NumberBox = function(config){
21053     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21054     
21055 };
21056
21057 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
21058     
21059     headline : '',
21060     content : '',
21061     icon : '',
21062     footer : '',
21063     fhref : '',
21064     ficon : '',
21065     
21066     getAutoCreate : function(){
21067         
21068         var cfg = {
21069             tag : 'div',
21070             cls : 'small-box ',
21071             cn : [
21072                 {
21073                     tag : 'div',
21074                     cls : 'inner',
21075                     cn :[
21076                         {
21077                             tag : 'h3',
21078                             cls : 'roo-headline',
21079                             html : this.headline
21080                         },
21081                         {
21082                             tag : 'p',
21083                             cls : 'roo-content',
21084                             html : this.content
21085                         }
21086                     ]
21087                 }
21088             ]
21089         }
21090         
21091         if(this.icon){
21092             cfg.cn.push({
21093                 tag : 'div',
21094                 cls : 'icon',
21095                 cn :[
21096                     {
21097                         tag : 'i',
21098                         cls : 'ion ' + this.icon
21099                     }
21100                 ]
21101             });
21102         }
21103         
21104         if(this.footer){
21105             var footer = {
21106                 tag : 'a',
21107                 cls : 'small-box-footer',
21108                 href : this.fhref || '#',
21109                 html : this.footer
21110             };
21111             
21112             cfg.cn.push(footer);
21113             
21114         }
21115         
21116         return  cfg;
21117     },
21118
21119     onRender : function(ct,position){
21120         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21121
21122
21123        
21124                 
21125     },
21126
21127     setHeadline: function (value)
21128     {
21129         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21130     },
21131     
21132     setFooter: function (value, href)
21133     {
21134         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21135         
21136         if(href){
21137             this.el.select('a.small-box-footer',true).first().attr('href', href);
21138         }
21139         
21140     },
21141
21142     setContent: function (value)
21143     {
21144         this.el.select('.roo-content',true).first().dom.innerHTML = value;
21145     },
21146
21147     initEvents: function() 
21148     {   
21149         
21150     }
21151     
21152 });
21153
21154  
21155 /*
21156  * - LGPL
21157  *
21158  * TabBox
21159  * 
21160  */
21161 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21162
21163 /**
21164  * @class Roo.bootstrap.dash.TabBox
21165  * @extends Roo.bootstrap.Component
21166  * Bootstrap TabBox class
21167  * @cfg {String} title Title of the TabBox
21168  * @cfg {String} icon Icon of the TabBox
21169  * @cfg {Boolean} showtabs (true|false) show the tabs default true
21170  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21171  * 
21172  * @constructor
21173  * Create a new TabBox
21174  * @param {Object} config The config object
21175  */
21176
21177
21178 Roo.bootstrap.dash.TabBox = function(config){
21179     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21180     this.addEvents({
21181         // raw events
21182         /**
21183          * @event addpane
21184          * When a pane is added
21185          * @param {Roo.bootstrap.dash.TabPane} pane
21186          */
21187         "addpane" : true,
21188         /**
21189          * @event activatepane
21190          * When a pane is activated
21191          * @param {Roo.bootstrap.dash.TabPane} pane
21192          */
21193         "activatepane" : true
21194         
21195          
21196     });
21197     
21198     this.panes = [];
21199 };
21200
21201 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
21202
21203     title : '',
21204     icon : false,
21205     showtabs : true,
21206     tabScrollable : false,
21207     
21208     getChildContainer : function()
21209     {
21210         return this.el.select('.tab-content', true).first();
21211     },
21212     
21213     getAutoCreate : function(){
21214         
21215         var header = {
21216             tag: 'li',
21217             cls: 'pull-left header',
21218             html: this.title,
21219             cn : []
21220         };
21221         
21222         if(this.icon){
21223             header.cn.push({
21224                 tag: 'i',
21225                 cls: 'fa ' + this.icon
21226             });
21227         }
21228         
21229         var h = {
21230             tag: 'ul',
21231             cls: 'nav nav-tabs pull-right',
21232             cn: [
21233                 header
21234             ]
21235         };
21236         
21237         if(this.tabScrollable){
21238             h = {
21239                 tag: 'div',
21240                 cls: 'tab-header',
21241                 cn: [
21242                     {
21243                         tag: 'ul',
21244                         cls: 'nav nav-tabs pull-right',
21245                         cn: [
21246                             header
21247                         ]
21248                     }
21249                 ]
21250             }
21251         }
21252         
21253         var cfg = {
21254             tag: 'div',
21255             cls: 'nav-tabs-custom',
21256             cn: [
21257                 h,
21258                 {
21259                     tag: 'div',
21260                     cls: 'tab-content no-padding',
21261                     cn: []
21262                 }
21263             ]
21264         }
21265
21266         return  cfg;
21267     },
21268     initEvents : function()
21269     {
21270         //Roo.log('add add pane handler');
21271         this.on('addpane', this.onAddPane, this);
21272     },
21273      /**
21274      * Updates the box title
21275      * @param {String} html to set the title to.
21276      */
21277     setTitle : function(value)
21278     {
21279         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21280     },
21281     onAddPane : function(pane)
21282     {
21283         this.panes.push(pane);
21284         //Roo.log('addpane');
21285         //Roo.log(pane);
21286         // tabs are rendere left to right..
21287         if(!this.showtabs){
21288             return;
21289         }
21290         
21291         var ctr = this.el.select('.nav-tabs', true).first();
21292          
21293          
21294         var existing = ctr.select('.nav-tab',true);
21295         var qty = existing.getCount();;
21296         
21297         
21298         var tab = ctr.createChild({
21299             tag : 'li',
21300             cls : 'nav-tab' + (qty ? '' : ' active'),
21301             cn : [
21302                 {
21303                     tag : 'a',
21304                     href:'#',
21305                     html : pane.title
21306                 }
21307             ]
21308         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21309         pane.tab = tab;
21310         
21311         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21312         if (!qty) {
21313             pane.el.addClass('active');
21314         }
21315         
21316                 
21317     },
21318     onTabClick : function(ev,un,ob,pane)
21319     {
21320         //Roo.log('tab - prev default');
21321         ev.preventDefault();
21322         
21323         
21324         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21325         pane.tab.addClass('active');
21326         //Roo.log(pane.title);
21327         this.getChildContainer().select('.tab-pane',true).removeClass('active');
21328         // technically we should have a deactivate event.. but maybe add later.
21329         // and it should not de-activate the selected tab...
21330         this.fireEvent('activatepane', pane);
21331         pane.el.addClass('active');
21332         pane.fireEvent('activate');
21333         
21334         
21335     },
21336     
21337     getActivePane : function()
21338     {
21339         var r = false;
21340         Roo.each(this.panes, function(p) {
21341             if(p.el.hasClass('active')){
21342                 r = p;
21343                 return false;
21344             }
21345             
21346             return;
21347         });
21348         
21349         return r;
21350     }
21351     
21352     
21353 });
21354
21355  
21356 /*
21357  * - LGPL
21358  *
21359  * Tab pane
21360  * 
21361  */
21362 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21363 /**
21364  * @class Roo.bootstrap.TabPane
21365  * @extends Roo.bootstrap.Component
21366  * Bootstrap TabPane class
21367  * @cfg {Boolean} active (false | true) Default false
21368  * @cfg {String} title title of panel
21369
21370  * 
21371  * @constructor
21372  * Create a new TabPane
21373  * @param {Object} config The config object
21374  */
21375
21376 Roo.bootstrap.dash.TabPane = function(config){
21377     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21378     
21379     this.addEvents({
21380         // raw events
21381         /**
21382          * @event activate
21383          * When a pane is activated
21384          * @param {Roo.bootstrap.dash.TabPane} pane
21385          */
21386         "activate" : true
21387          
21388     });
21389 };
21390
21391 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
21392     
21393     active : false,
21394     title : '',
21395     
21396     // the tabBox that this is attached to.
21397     tab : false,
21398      
21399     getAutoCreate : function() 
21400     {
21401         var cfg = {
21402             tag: 'div',
21403             cls: 'tab-pane'
21404         }
21405         
21406         if(this.active){
21407             cfg.cls += ' active';
21408         }
21409         
21410         return cfg;
21411     },
21412     initEvents  : function()
21413     {
21414         //Roo.log('trigger add pane handler');
21415         this.parent().fireEvent('addpane', this)
21416     },
21417     
21418      /**
21419      * Updates the tab title 
21420      * @param {String} html to set the title to.
21421      */
21422     setTitle: function(str)
21423     {
21424         if (!this.tab) {
21425             return;
21426         }
21427         this.title = str;
21428         this.tab.select('a', true).first().dom.innerHTML = str;
21429         
21430     }
21431     
21432     
21433     
21434 });
21435
21436  
21437
21438
21439  /*
21440  * - LGPL
21441  *
21442  * menu
21443  * 
21444  */
21445 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21446
21447 /**
21448  * @class Roo.bootstrap.menu.Menu
21449  * @extends Roo.bootstrap.Component
21450  * Bootstrap Menu class - container for Menu
21451  * @cfg {String} html Text of the menu
21452  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21453  * @cfg {String} icon Font awesome icon
21454  * @cfg {String} pos Menu align to (top | bottom) default bottom
21455  * 
21456  * 
21457  * @constructor
21458  * Create a new Menu
21459  * @param {Object} config The config object
21460  */
21461
21462
21463 Roo.bootstrap.menu.Menu = function(config){
21464     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21465     
21466     this.addEvents({
21467         /**
21468          * @event beforeshow
21469          * Fires before this menu is displayed
21470          * @param {Roo.bootstrap.menu.Menu} this
21471          */
21472         beforeshow : true,
21473         /**
21474          * @event beforehide
21475          * Fires before this menu is hidden
21476          * @param {Roo.bootstrap.menu.Menu} this
21477          */
21478         beforehide : true,
21479         /**
21480          * @event show
21481          * Fires after this menu is displayed
21482          * @param {Roo.bootstrap.menu.Menu} this
21483          */
21484         show : true,
21485         /**
21486          * @event hide
21487          * Fires after this menu is hidden
21488          * @param {Roo.bootstrap.menu.Menu} this
21489          */
21490         hide : true,
21491         /**
21492          * @event click
21493          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21494          * @param {Roo.bootstrap.menu.Menu} this
21495          * @param {Roo.EventObject} e
21496          */
21497         click : true
21498     });
21499     
21500 };
21501
21502 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
21503     
21504     submenu : false,
21505     html : '',
21506     weight : 'default',
21507     icon : false,
21508     pos : 'bottom',
21509     
21510     
21511     getChildContainer : function() {
21512         if(this.isSubMenu){
21513             return this.el;
21514         }
21515         
21516         return this.el.select('ul.dropdown-menu', true).first();  
21517     },
21518     
21519     getAutoCreate : function()
21520     {
21521         var text = [
21522             {
21523                 tag : 'span',
21524                 cls : 'roo-menu-text',
21525                 html : this.html
21526             }
21527         ];
21528         
21529         if(this.icon){
21530             text.unshift({
21531                 tag : 'i',
21532                 cls : 'fa ' + this.icon
21533             })
21534         }
21535         
21536         
21537         var cfg = {
21538             tag : 'div',
21539             cls : 'btn-group',
21540             cn : [
21541                 {
21542                     tag : 'button',
21543                     cls : 'dropdown-button btn btn-' + this.weight,
21544                     cn : text
21545                 },
21546                 {
21547                     tag : 'button',
21548                     cls : 'dropdown-toggle btn btn-' + this.weight,
21549                     cn : [
21550                         {
21551                             tag : 'span',
21552                             cls : 'caret'
21553                         }
21554                     ]
21555                 },
21556                 {
21557                     tag : 'ul',
21558                     cls : 'dropdown-menu'
21559                 }
21560             ]
21561             
21562         };
21563         
21564         if(this.pos == 'top'){
21565             cfg.cls += ' dropup';
21566         }
21567         
21568         if(this.isSubMenu){
21569             cfg = {
21570                 tag : 'ul',
21571                 cls : 'dropdown-menu'
21572             }
21573         }
21574         
21575         return cfg;
21576     },
21577     
21578     onRender : function(ct, position)
21579     {
21580         this.isSubMenu = ct.hasClass('dropdown-submenu');
21581         
21582         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21583     },
21584     
21585     initEvents : function() 
21586     {
21587         if(this.isSubMenu){
21588             return;
21589         }
21590         
21591         this.hidden = true;
21592         
21593         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21594         this.triggerEl.on('click', this.onTriggerPress, this);
21595         
21596         this.buttonEl = this.el.select('button.dropdown-button', true).first();
21597         this.buttonEl.on('click', this.onClick, this);
21598         
21599     },
21600     
21601     list : function()
21602     {
21603         if(this.isSubMenu){
21604             return this.el;
21605         }
21606         
21607         return this.el.select('ul.dropdown-menu', true).first();
21608     },
21609     
21610     onClick : function(e)
21611     {
21612         this.fireEvent("click", this, e);
21613     },
21614     
21615     onTriggerPress  : function(e)
21616     {   
21617         if (this.isVisible()) {
21618             this.hide();
21619         } else {
21620             this.show();
21621         }
21622     },
21623     
21624     isVisible : function(){
21625         return !this.hidden;
21626     },
21627     
21628     show : function()
21629     {
21630         this.fireEvent("beforeshow", this);
21631         
21632         this.hidden = false;
21633         this.el.addClass('open');
21634         
21635         Roo.get(document).on("mouseup", this.onMouseUp, this);
21636         
21637         this.fireEvent("show", this);
21638         
21639         
21640     },
21641     
21642     hide : function()
21643     {
21644         this.fireEvent("beforehide", this);
21645         
21646         this.hidden = true;
21647         this.el.removeClass('open');
21648         
21649         Roo.get(document).un("mouseup", this.onMouseUp);
21650         
21651         this.fireEvent("hide", this);
21652     },
21653     
21654     onMouseUp : function()
21655     {
21656         this.hide();
21657     }
21658     
21659 });
21660
21661  
21662  /*
21663  * - LGPL
21664  *
21665  * menu item
21666  * 
21667  */
21668 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21669
21670 /**
21671  * @class Roo.bootstrap.menu.Item
21672  * @extends Roo.bootstrap.Component
21673  * Bootstrap MenuItem class
21674  * @cfg {Boolean} submenu (true | false) default false
21675  * @cfg {String} html text of the item
21676  * @cfg {String} href the link
21677  * @cfg {Boolean} disable (true | false) default false
21678  * @cfg {Boolean} preventDefault (true | false) default true
21679  * @cfg {String} icon Font awesome icon
21680  * @cfg {String} pos Submenu align to (left | right) default right 
21681  * 
21682  * 
21683  * @constructor
21684  * Create a new Item
21685  * @param {Object} config The config object
21686  */
21687
21688
21689 Roo.bootstrap.menu.Item = function(config){
21690     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21691     this.addEvents({
21692         /**
21693          * @event mouseover
21694          * Fires when the mouse is hovering over this menu
21695          * @param {Roo.bootstrap.menu.Item} this
21696          * @param {Roo.EventObject} e
21697          */
21698         mouseover : true,
21699         /**
21700          * @event mouseout
21701          * Fires when the mouse exits this menu
21702          * @param {Roo.bootstrap.menu.Item} this
21703          * @param {Roo.EventObject} e
21704          */
21705         mouseout : true,
21706         // raw events
21707         /**
21708          * @event click
21709          * The raw click event for the entire grid.
21710          * @param {Roo.EventObject} e
21711          */
21712         click : true
21713     });
21714 };
21715
21716 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
21717     
21718     submenu : false,
21719     href : '',
21720     html : '',
21721     preventDefault: true,
21722     disable : false,
21723     icon : false,
21724     pos : 'right',
21725     
21726     getAutoCreate : function()
21727     {
21728         var text = [
21729             {
21730                 tag : 'span',
21731                 cls : 'roo-menu-item-text',
21732                 html : this.html
21733             }
21734         ];
21735         
21736         if(this.icon){
21737             text.unshift({
21738                 tag : 'i',
21739                 cls : 'fa ' + this.icon
21740             })
21741         }
21742         
21743         var cfg = {
21744             tag : 'li',
21745             cn : [
21746                 {
21747                     tag : 'a',
21748                     href : this.href || '#',
21749                     cn : text
21750                 }
21751             ]
21752         };
21753         
21754         if(this.disable){
21755             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21756         }
21757         
21758         if(this.submenu){
21759             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21760             
21761             if(this.pos == 'left'){
21762                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21763             }
21764         }
21765         
21766         return cfg;
21767     },
21768     
21769     initEvents : function() 
21770     {
21771         this.el.on('mouseover', this.onMouseOver, this);
21772         this.el.on('mouseout', this.onMouseOut, this);
21773         
21774         this.el.select('a', true).first().on('click', this.onClick, this);
21775         
21776     },
21777     
21778     onClick : function(e)
21779     {
21780         if(this.preventDefault){
21781             e.preventDefault();
21782         }
21783         
21784         this.fireEvent("click", this, e);
21785     },
21786     
21787     onMouseOver : function(e)
21788     {
21789         if(this.submenu && this.pos == 'left'){
21790             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21791         }
21792         
21793         this.fireEvent("mouseover", this, e);
21794     },
21795     
21796     onMouseOut : function(e)
21797     {
21798         this.fireEvent("mouseout", this, e);
21799     }
21800 });
21801
21802  
21803
21804  /*
21805  * - LGPL
21806  *
21807  * menu separator
21808  * 
21809  */
21810 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21811
21812 /**
21813  * @class Roo.bootstrap.menu.Separator
21814  * @extends Roo.bootstrap.Component
21815  * Bootstrap Separator class
21816  * 
21817  * @constructor
21818  * Create a new Separator
21819  * @param {Object} config The config object
21820  */
21821
21822
21823 Roo.bootstrap.menu.Separator = function(config){
21824     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21825 };
21826
21827 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
21828     
21829     getAutoCreate : function(){
21830         var cfg = {
21831             tag : 'li',
21832             cls: 'divider'
21833         };
21834         
21835         return cfg;
21836     }
21837    
21838 });
21839
21840  
21841
21842  /*
21843  * - LGPL
21844  *
21845  * Tooltip
21846  * 
21847  */
21848
21849 /**
21850  * @class Roo.bootstrap.Tooltip
21851  * Bootstrap Tooltip class
21852  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21853  * to determine which dom element triggers the tooltip.
21854  * 
21855  * It needs to add support for additional attributes like tooltip-position
21856  * 
21857  * @constructor
21858  * Create a new Toolti
21859  * @param {Object} config The config object
21860  */
21861
21862 Roo.bootstrap.Tooltip = function(config){
21863     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21864 };
21865
21866 Roo.apply(Roo.bootstrap.Tooltip, {
21867     /**
21868      * @function init initialize tooltip monitoring.
21869      * @static
21870      */
21871     currentEl : false,
21872     currentTip : false,
21873     currentRegion : false,
21874     
21875     //  init : delay?
21876     
21877     init : function()
21878     {
21879         Roo.get(document).on('mouseover', this.enter ,this);
21880         Roo.get(document).on('mouseout', this.leave, this);
21881          
21882         
21883         this.currentTip = new Roo.bootstrap.Tooltip();
21884     },
21885     
21886     enter : function(ev)
21887     {
21888         var dom = ev.getTarget();
21889         
21890         //Roo.log(['enter',dom]);
21891         var el = Roo.fly(dom);
21892         if (this.currentEl) {
21893             //Roo.log(dom);
21894             //Roo.log(this.currentEl);
21895             //Roo.log(this.currentEl.contains(dom));
21896             if (this.currentEl == el) {
21897                 return;
21898             }
21899             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21900                 return;
21901             }
21902
21903         }
21904         
21905         
21906         
21907         if (this.currentTip.el) {
21908             this.currentTip.el.hide(); // force hiding...
21909         }    
21910         //Roo.log(ev);
21911         var bindEl = el;
21912         
21913         // you can not look for children, as if el is the body.. then everythign is the child..
21914         if (!el.attr('tooltip')) { //
21915             if (!el.select("[tooltip]").elements.length) {
21916                 return;
21917             }
21918             // is the mouse over this child...?
21919             bindEl = el.select("[tooltip]").first();
21920             var xy = ev.getXY();
21921             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
21922                 //Roo.log("not in region.");
21923                 return;
21924             }
21925             //Roo.log("child element over..");
21926             
21927         }
21928         this.currentEl = bindEl;
21929         this.currentTip.bind(bindEl);
21930         this.currentRegion = Roo.lib.Region.getRegion(dom);
21931         this.currentTip.enter();
21932         
21933     },
21934     leave : function(ev)
21935     {
21936         var dom = ev.getTarget();
21937         //Roo.log(['leave',dom]);
21938         if (!this.currentEl) {
21939             return;
21940         }
21941         
21942         
21943         if (dom != this.currentEl.dom) {
21944             return;
21945         }
21946         var xy = ev.getXY();
21947         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
21948             return;
21949         }
21950         // only activate leave if mouse cursor is outside... bounding box..
21951         
21952         
21953         
21954         
21955         if (this.currentTip) {
21956             this.currentTip.leave();
21957         }
21958         //Roo.log('clear currentEl');
21959         this.currentEl = false;
21960         
21961         
21962     },
21963     alignment : {
21964         'left' : ['r-l', [-2,0], 'right'],
21965         'right' : ['l-r', [2,0], 'left'],
21966         'bottom' : ['t-b', [0,2], 'top'],
21967         'top' : [ 'b-t', [0,-2], 'bottom']
21968     }
21969     
21970 });
21971
21972
21973 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
21974     
21975     
21976     bindEl : false,
21977     
21978     delay : null, // can be { show : 300 , hide: 500}
21979     
21980     timeout : null,
21981     
21982     hoverState : null, //???
21983     
21984     placement : 'bottom', 
21985     
21986     getAutoCreate : function(){
21987     
21988         var cfg = {
21989            cls : 'tooltip',
21990            role : 'tooltip',
21991            cn : [
21992                 {
21993                     cls : 'tooltip-arrow'
21994                 },
21995                 {
21996                     cls : 'tooltip-inner'
21997                 }
21998            ]
21999         };
22000         
22001         return cfg;
22002     },
22003     bind : function(el)
22004     {
22005         this.bindEl = el;
22006     },
22007       
22008     
22009     enter : function () {
22010        
22011         if (this.timeout != null) {
22012             clearTimeout(this.timeout);
22013         }
22014         
22015         this.hoverState = 'in';
22016          //Roo.log("enter - show");
22017         if (!this.delay || !this.delay.show) {
22018             this.show();
22019             return;
22020         }
22021         var _t = this;
22022         this.timeout = setTimeout(function () {
22023             if (_t.hoverState == 'in') {
22024                 _t.show();
22025             }
22026         }, this.delay.show);
22027     },
22028     leave : function()
22029     {
22030         clearTimeout(this.timeout);
22031     
22032         this.hoverState = 'out';
22033          if (!this.delay || !this.delay.hide) {
22034             this.hide();
22035             return;
22036         }
22037        
22038         var _t = this;
22039         this.timeout = setTimeout(function () {
22040             //Roo.log("leave - timeout");
22041             
22042             if (_t.hoverState == 'out') {
22043                 _t.hide();
22044                 Roo.bootstrap.Tooltip.currentEl = false;
22045             }
22046         }, delay);
22047     },
22048     
22049     show : function ()
22050     {
22051         if (!this.el) {
22052             this.render(document.body);
22053         }
22054         // set content.
22055         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22056         
22057         var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22058         
22059         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22060         
22061         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22062         
22063         var placement = typeof this.placement == 'function' ?
22064             this.placement.call(this, this.el, on_el) :
22065             this.placement;
22066             
22067         var autoToken = /\s?auto?\s?/i;
22068         var autoPlace = autoToken.test(placement);
22069         if (autoPlace) {
22070             placement = placement.replace(autoToken, '') || 'top';
22071         }
22072         
22073         //this.el.detach()
22074         //this.el.setXY([0,0]);
22075         this.el.show();
22076         //this.el.dom.style.display='block';
22077         this.el.addClass(placement);
22078         
22079         //this.el.appendTo(on_el);
22080         
22081         var p = this.getPosition();
22082         var box = this.el.getBox();
22083         
22084         if (autoPlace) {
22085             // fixme..
22086         }
22087         var align = Roo.bootstrap.Tooltip.alignment[placement];
22088         this.el.alignTo(this.bindEl, align[0],align[1]);
22089         //var arrow = this.el.select('.arrow',true).first();
22090         //arrow.set(align[2], 
22091         
22092         this.el.addClass('in fade');
22093         this.hoverState = null;
22094         
22095         if (this.el.hasClass('fade')) {
22096             // fade it?
22097         }
22098         
22099     },
22100     hide : function()
22101     {
22102          
22103         if (!this.el) {
22104             return;
22105         }
22106         //this.el.setXY([0,0]);
22107         this.el.removeClass('in');
22108         //this.el.hide();
22109         
22110     }
22111     
22112 });
22113  
22114
22115  /*
22116  * - LGPL
22117  *
22118  * Location Picker
22119  * 
22120  */
22121
22122 /**
22123  * @class Roo.bootstrap.LocationPicker
22124  * @extends Roo.bootstrap.Component
22125  * Bootstrap LocationPicker class
22126  * @cfg {Number} latitude Position when init default 0
22127  * @cfg {Number} longitude Position when init default 0
22128  * @cfg {Number} zoom default 15
22129  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22130  * @cfg {Boolean} mapTypeControl default false
22131  * @cfg {Boolean} disableDoubleClickZoom default false
22132  * @cfg {Boolean} scrollwheel default true
22133  * @cfg {Boolean} streetViewControl default false
22134  * @cfg {Number} radius default 0
22135  * @cfg {String} locationName
22136  * @cfg {Boolean} draggable default true
22137  * @cfg {Boolean} enableAutocomplete default false
22138  * @cfg {Boolean} enableReverseGeocode default true
22139  * @cfg {String} markerTitle
22140  * 
22141  * @constructor
22142  * Create a new LocationPicker
22143  * @param {Object} config The config object
22144  */
22145
22146
22147 Roo.bootstrap.LocationPicker = function(config){
22148     
22149     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22150     
22151     this.addEvents({
22152         /**
22153          * @event initial
22154          * Fires when the picker initialized.
22155          * @param {Roo.bootstrap.LocationPicker} this
22156          * @param {Google Location} location
22157          */
22158         initial : true,
22159         /**
22160          * @event positionchanged
22161          * Fires when the picker position changed.
22162          * @param {Roo.bootstrap.LocationPicker} this
22163          * @param {Google Location} location
22164          */
22165         positionchanged : true,
22166         /**
22167          * @event resize
22168          * Fires when the map resize.
22169          * @param {Roo.bootstrap.LocationPicker} this
22170          */
22171         resize : true,
22172         /**
22173          * @event show
22174          * Fires when the map show.
22175          * @param {Roo.bootstrap.LocationPicker} this
22176          */
22177         show : true,
22178         /**
22179          * @event hide
22180          * Fires when the map hide.
22181          * @param {Roo.bootstrap.LocationPicker} this
22182          */
22183         hide : true,
22184         /**
22185          * @event mapClick
22186          * Fires when click the map.
22187          * @param {Roo.bootstrap.LocationPicker} this
22188          * @param {Map event} e
22189          */
22190         mapClick : true,
22191         /**
22192          * @event mapRightClick
22193          * Fires when right click the map.
22194          * @param {Roo.bootstrap.LocationPicker} this
22195          * @param {Map event} e
22196          */
22197         mapRightClick : true,
22198         /**
22199          * @event markerClick
22200          * Fires when click the marker.
22201          * @param {Roo.bootstrap.LocationPicker} this
22202          * @param {Map event} e
22203          */
22204         markerClick : true,
22205         /**
22206          * @event markerRightClick
22207          * Fires when right click the marker.
22208          * @param {Roo.bootstrap.LocationPicker} this
22209          * @param {Map event} e
22210          */
22211         markerRightClick : true,
22212         /**
22213          * @event OverlayViewDraw
22214          * Fires when OverlayView Draw
22215          * @param {Roo.bootstrap.LocationPicker} this
22216          */
22217         OverlayViewDraw : true,
22218         /**
22219          * @event OverlayViewOnAdd
22220          * Fires when OverlayView Draw
22221          * @param {Roo.bootstrap.LocationPicker} this
22222          */
22223         OverlayViewOnAdd : true,
22224         /**
22225          * @event OverlayViewOnRemove
22226          * Fires when OverlayView Draw
22227          * @param {Roo.bootstrap.LocationPicker} this
22228          */
22229         OverlayViewOnRemove : true,
22230         /**
22231          * @event OverlayViewShow
22232          * Fires when OverlayView Draw
22233          * @param {Roo.bootstrap.LocationPicker} this
22234          * @param {Pixel} cpx
22235          */
22236         OverlayViewShow : true,
22237         /**
22238          * @event OverlayViewHide
22239          * Fires when OverlayView Draw
22240          * @param {Roo.bootstrap.LocationPicker} this
22241          */
22242         OverlayViewHide : true
22243     });
22244         
22245 };
22246
22247 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
22248     
22249     gMapContext: false,
22250     
22251     latitude: 0,
22252     longitude: 0,
22253     zoom: 15,
22254     mapTypeId: false,
22255     mapTypeControl: false,
22256     disableDoubleClickZoom: false,
22257     scrollwheel: true,
22258     streetViewControl: false,
22259     radius: 0,
22260     locationName: '',
22261     draggable: true,
22262     enableAutocomplete: false,
22263     enableReverseGeocode: true,
22264     markerTitle: '',
22265     
22266     getAutoCreate: function()
22267     {
22268
22269         var cfg = {
22270             tag: 'div',
22271             cls: 'roo-location-picker'
22272         };
22273         
22274         return cfg
22275     },
22276     
22277     initEvents: function(ct, position)
22278     {       
22279         if(!this.el.getWidth() || this.isApplied()){
22280             return;
22281         }
22282         
22283         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22284         
22285         this.initial();
22286     },
22287     
22288     initial: function()
22289     {
22290         if(!this.mapTypeId){
22291             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22292         }
22293         
22294         this.gMapContext = this.GMapContext();
22295         
22296         this.initOverlayView();
22297         
22298         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22299         
22300         var _this = this;
22301                 
22302         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22303             _this.setPosition(_this.gMapContext.marker.position);
22304         });
22305         
22306         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22307             _this.fireEvent('mapClick', this, event);
22308             
22309         });
22310
22311         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22312             _this.fireEvent('mapRightClick', this, event);
22313             
22314         });
22315         
22316         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22317             _this.fireEvent('markerClick', this, event);
22318             
22319         });
22320
22321         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22322             _this.fireEvent('markerRightClick', this, event);
22323             
22324         });
22325         
22326         this.setPosition(this.gMapContext.location);
22327         
22328         this.fireEvent('initial', this, this.gMapContext.location);
22329     },
22330     
22331     initOverlayView: function()
22332     {
22333         var _this = this;
22334         
22335         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22336             
22337             draw: function()
22338             {
22339                 _this.fireEvent('OverlayViewDraw', _this);
22340             },
22341             
22342             onAdd: function()
22343             {
22344                 _this.fireEvent('OverlayViewOnAdd', _this);
22345             },
22346             
22347             onRemove: function()
22348             {
22349                 _this.fireEvent('OverlayViewOnRemove', _this);
22350             },
22351             
22352             show: function(cpx)
22353             {
22354                 _this.fireEvent('OverlayViewShow', _this, cpx);
22355             },
22356             
22357             hide: function()
22358             {
22359                 _this.fireEvent('OverlayViewHide', _this);
22360             }
22361             
22362         });
22363     },
22364     
22365     fromLatLngToContainerPixel: function(event)
22366     {
22367         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22368     },
22369     
22370     isApplied: function() 
22371     {
22372         return this.getGmapContext() == false ? false : true;
22373     },
22374     
22375     getGmapContext: function() 
22376     {
22377         return this.gMapContext
22378     },
22379     
22380     GMapContext: function() 
22381     {
22382         var position = new google.maps.LatLng(this.latitude, this.longitude);
22383         
22384         var _map = new google.maps.Map(this.el.dom, {
22385             center: position,
22386             zoom: this.zoom,
22387             mapTypeId: this.mapTypeId,
22388             mapTypeControl: this.mapTypeControl,
22389             disableDoubleClickZoom: this.disableDoubleClickZoom,
22390             scrollwheel: this.scrollwheel,
22391             streetViewControl: this.streetViewControl,
22392             locationName: this.locationName,
22393             draggable: this.draggable,
22394             enableAutocomplete: this.enableAutocomplete,
22395             enableReverseGeocode: this.enableReverseGeocode
22396         });
22397         
22398         var _marker = new google.maps.Marker({
22399             position: position,
22400             map: _map,
22401             title: this.markerTitle,
22402             draggable: this.draggable
22403         });
22404         
22405         return {
22406             map: _map,
22407             marker: _marker,
22408             circle: null,
22409             location: position,
22410             radius: this.radius,
22411             locationName: this.locationName,
22412             addressComponents: {
22413                 formatted_address: null,
22414                 addressLine1: null,
22415                 addressLine2: null,
22416                 streetName: null,
22417                 streetNumber: null,
22418                 city: null,
22419                 district: null,
22420                 state: null,
22421                 stateOrProvince: null
22422             },
22423             settings: this,
22424             domContainer: this.el.dom,
22425             geodecoder: new google.maps.Geocoder()
22426         };
22427     },
22428     
22429     drawCircle: function(center, radius, options) 
22430     {
22431         if (this.gMapContext.circle != null) {
22432             this.gMapContext.circle.setMap(null);
22433         }
22434         if (radius > 0) {
22435             radius *= 1;
22436             options = Roo.apply({}, options, {
22437                 strokeColor: "#0000FF",
22438                 strokeOpacity: .35,
22439                 strokeWeight: 2,
22440                 fillColor: "#0000FF",
22441                 fillOpacity: .2
22442             });
22443             
22444             options.map = this.gMapContext.map;
22445             options.radius = radius;
22446             options.center = center;
22447             this.gMapContext.circle = new google.maps.Circle(options);
22448             return this.gMapContext.circle;
22449         }
22450         
22451         return null;
22452     },
22453     
22454     setPosition: function(location) 
22455     {
22456         this.gMapContext.location = location;
22457         this.gMapContext.marker.setPosition(location);
22458         this.gMapContext.map.panTo(location);
22459         this.drawCircle(location, this.gMapContext.radius, {});
22460         
22461         var _this = this;
22462         
22463         if (this.gMapContext.settings.enableReverseGeocode) {
22464             this.gMapContext.geodecoder.geocode({
22465                 latLng: this.gMapContext.location
22466             }, function(results, status) {
22467                 
22468                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22469                     _this.gMapContext.locationName = results[0].formatted_address;
22470                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22471                     
22472                     _this.fireEvent('positionchanged', this, location);
22473                 }
22474             });
22475             
22476             return;
22477         }
22478         
22479         this.fireEvent('positionchanged', this, location);
22480     },
22481     
22482     resize: function()
22483     {
22484         google.maps.event.trigger(this.gMapContext.map, "resize");
22485         
22486         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22487         
22488         this.fireEvent('resize', this);
22489     },
22490     
22491     setPositionByLatLng: function(latitude, longitude)
22492     {
22493         this.setPosition(new google.maps.LatLng(latitude, longitude));
22494     },
22495     
22496     getCurrentPosition: function() 
22497     {
22498         return {
22499             latitude: this.gMapContext.location.lat(),
22500             longitude: this.gMapContext.location.lng()
22501         };
22502     },
22503     
22504     getAddressName: function() 
22505     {
22506         return this.gMapContext.locationName;
22507     },
22508     
22509     getAddressComponents: function() 
22510     {
22511         return this.gMapContext.addressComponents;
22512     },
22513     
22514     address_component_from_google_geocode: function(address_components) 
22515     {
22516         var result = {};
22517         
22518         for (var i = 0; i < address_components.length; i++) {
22519             var component = address_components[i];
22520             if (component.types.indexOf("postal_code") >= 0) {
22521                 result.postalCode = component.short_name;
22522             } else if (component.types.indexOf("street_number") >= 0) {
22523                 result.streetNumber = component.short_name;
22524             } else if (component.types.indexOf("route") >= 0) {
22525                 result.streetName = component.short_name;
22526             } else if (component.types.indexOf("neighborhood") >= 0) {
22527                 result.city = component.short_name;
22528             } else if (component.types.indexOf("locality") >= 0) {
22529                 result.city = component.short_name;
22530             } else if (component.types.indexOf("sublocality") >= 0) {
22531                 result.district = component.short_name;
22532             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22533                 result.stateOrProvince = component.short_name;
22534             } else if (component.types.indexOf("country") >= 0) {
22535                 result.country = component.short_name;
22536             }
22537         }
22538         
22539         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22540         result.addressLine2 = "";
22541         return result;
22542     },
22543     
22544     setZoomLevel: function(zoom)
22545     {
22546         this.gMapContext.map.setZoom(zoom);
22547     },
22548     
22549     show: function()
22550     {
22551         if(!this.el){
22552             return;
22553         }
22554         
22555         this.el.show();
22556         
22557         this.resize();
22558         
22559         this.fireEvent('show', this);
22560     },
22561     
22562     hide: function()
22563     {
22564         if(!this.el){
22565             return;
22566         }
22567         
22568         this.el.hide();
22569         
22570         this.fireEvent('hide', this);
22571     }
22572     
22573 });
22574
22575 Roo.apply(Roo.bootstrap.LocationPicker, {
22576     
22577     OverlayView : function(map, options)
22578     {
22579         options = options || {};
22580         
22581         this.setMap(map);
22582     }
22583     
22584     
22585 });/*
22586  * - LGPL
22587  *
22588  * Alert
22589  * 
22590  */
22591
22592 /**
22593  * @class Roo.bootstrap.Alert
22594  * @extends Roo.bootstrap.Component
22595  * Bootstrap Alert class
22596  * @cfg {String} title The title of alert
22597  * @cfg {String} html The content of alert
22598  * @cfg {String} weight (  success | info | warning | danger )
22599  * @cfg {String} faicon font-awesomeicon
22600  * 
22601  * @constructor
22602  * Create a new alert
22603  * @param {Object} config The config object
22604  */
22605
22606
22607 Roo.bootstrap.Alert = function(config){
22608     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22609     
22610 };
22611
22612 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
22613     
22614     title: '',
22615     html: '',
22616     weight: false,
22617     faicon: false,
22618     
22619     getAutoCreate : function()
22620     {
22621         
22622         var cfg = {
22623             tag : 'div',
22624             cls : 'alert',
22625             cn : [
22626                 {
22627                     tag : 'i',
22628                     cls : 'roo-alert-icon'
22629                     
22630                 },
22631                 {
22632                     tag : 'b',
22633                     cls : 'roo-alert-title',
22634                     html : this.title
22635                 },
22636                 {
22637                     tag : 'span',
22638                     cls : 'roo-alert-text',
22639                     html : this.html
22640                 }
22641             ]
22642         };
22643         
22644         if(this.faicon){
22645             cfg.cn[0].cls += ' fa ' + this.faicon;
22646         }
22647         
22648         if(this.weight){
22649             cfg.cls += ' alert-' + this.weight;
22650         }
22651         
22652         return cfg;
22653     },
22654     
22655     initEvents: function() 
22656     {
22657         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22658     },
22659     
22660     setTitle : function(str)
22661     {
22662         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22663     },
22664     
22665     setText : function(str)
22666     {
22667         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22668     },
22669     
22670     setWeight : function(weight)
22671     {
22672         if(this.weight){
22673             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22674         }
22675         
22676         this.weight = weight;
22677         
22678         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22679     },
22680     
22681     setIcon : function(icon)
22682     {
22683         if(this.faicon){
22684             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22685         }
22686         
22687         this.faicon = icon
22688         
22689         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
22690     },
22691     
22692     hide: function() 
22693     {
22694         this.el.hide();   
22695     },
22696     
22697     show: function() 
22698     {  
22699         this.el.show();   
22700     }
22701     
22702 });
22703
22704