ec67842aaee0249bf58f81a91941b94abdc525b6
[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     getValue : function()
4210     {
4211         return this.el.dom.innerHTML;
4212     },
4213     
4214     setValue : function(value)
4215     {
4216         this.el.dom.innerHTML = value;
4217     }
4218    
4219 });
4220
4221  
4222
4223  /*
4224  * - LGPL
4225  *
4226  * pagination
4227  * 
4228  */
4229
4230 /**
4231  * @class Roo.bootstrap.Pagination
4232  * @extends Roo.bootstrap.Component
4233  * Bootstrap Pagination class
4234  * @cfg {String} size xs | sm | md | lg
4235  * @cfg {Boolean} inverse false | true
4236  * 
4237  * @constructor
4238  * Create a new Pagination
4239  * @param {Object} config The config object
4240  */
4241
4242 Roo.bootstrap.Pagination = function(config){
4243     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4244 };
4245
4246 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
4247     
4248     cls: false,
4249     size: false,
4250     inverse: false,
4251     
4252     getAutoCreate : function(){
4253         var cfg = {
4254             tag: 'ul',
4255                 cls: 'pagination'
4256         };
4257         if (this.inverse) {
4258             cfg.cls += ' inverse';
4259         }
4260         if (this.html) {
4261             cfg.html=this.html;
4262         }
4263         if (this.cls) {
4264             cfg.cls += " " + this.cls;
4265         }
4266         return cfg;
4267     }
4268    
4269 });
4270
4271  
4272
4273  /*
4274  * - LGPL
4275  *
4276  * Pagination item
4277  * 
4278  */
4279
4280
4281 /**
4282  * @class Roo.bootstrap.PaginationItem
4283  * @extends Roo.bootstrap.Component
4284  * Bootstrap PaginationItem class
4285  * @cfg {String} html text
4286  * @cfg {String} href the link
4287  * @cfg {Boolean} preventDefault (true | false) default true
4288  * @cfg {Boolean} active (true | false) default false
4289  * @cfg {Boolean} disabled default false
4290  * 
4291  * 
4292  * @constructor
4293  * Create a new PaginationItem
4294  * @param {Object} config The config object
4295  */
4296
4297
4298 Roo.bootstrap.PaginationItem = function(config){
4299     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4300     this.addEvents({
4301         // raw events
4302         /**
4303          * @event click
4304          * The raw click event for the entire grid.
4305          * @param {Roo.EventObject} e
4306          */
4307         "click" : true
4308     });
4309 };
4310
4311 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
4312     
4313     href : false,
4314     html : false,
4315     preventDefault: true,
4316     active : false,
4317     cls : false,
4318     disabled: false,
4319     
4320     getAutoCreate : function(){
4321         var cfg= {
4322             tag: 'li',
4323             cn: [
4324                 {
4325                     tag : 'a',
4326                     href : this.href ? this.href : '#',
4327                     html : this.html ? this.html : ''
4328                 }
4329             ]
4330         };
4331         
4332         if(this.cls){
4333             cfg.cls = this.cls;
4334         }
4335         
4336         if(this.disabled){
4337             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4338         }
4339         
4340         if(this.active){
4341             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4342         }
4343         
4344         return cfg;
4345     },
4346     
4347     initEvents: function() {
4348         
4349         this.el.on('click', this.onClick, this);
4350         
4351     },
4352     onClick : function(e)
4353     {
4354         Roo.log('PaginationItem on click ');
4355         if(this.preventDefault){
4356             e.preventDefault();
4357         }
4358         
4359         if(this.disabled){
4360             return;
4361         }
4362         
4363         this.fireEvent('click', this, e);
4364     }
4365    
4366 });
4367
4368  
4369
4370  /*
4371  * - LGPL
4372  *
4373  * slider
4374  * 
4375  */
4376
4377
4378 /**
4379  * @class Roo.bootstrap.Slider
4380  * @extends Roo.bootstrap.Component
4381  * Bootstrap Slider class
4382  *    
4383  * @constructor
4384  * Create a new Slider
4385  * @param {Object} config The config object
4386  */
4387
4388 Roo.bootstrap.Slider = function(config){
4389     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4390 };
4391
4392 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
4393     
4394     getAutoCreate : function(){
4395         
4396         var cfg = {
4397             tag: 'div',
4398             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4399             cn: [
4400                 {
4401                     tag: 'a',
4402                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
4403                 }
4404             ]
4405         }
4406         
4407         return cfg;
4408     }
4409    
4410 });
4411
4412  /*
4413  * Based on:
4414  * Ext JS Library 1.1.1
4415  * Copyright(c) 2006-2007, Ext JS, LLC.
4416  *
4417  * Originally Released Under LGPL - original licence link has changed is not relivant.
4418  *
4419  * Fork - LGPL
4420  * <script type="text/javascript">
4421  */
4422  
4423
4424 /**
4425  * @class Roo.grid.ColumnModel
4426  * @extends Roo.util.Observable
4427  * This is the default implementation of a ColumnModel used by the Grid. It defines
4428  * the columns in the grid.
4429  * <br>Usage:<br>
4430  <pre><code>
4431  var colModel = new Roo.grid.ColumnModel([
4432         {header: "Ticker", width: 60, sortable: true, locked: true},
4433         {header: "Company Name", width: 150, sortable: true},
4434         {header: "Market Cap.", width: 100, sortable: true},
4435         {header: "$ Sales", width: 100, sortable: true, renderer: money},
4436         {header: "Employees", width: 100, sortable: true, resizable: false}
4437  ]);
4438  </code></pre>
4439  * <p>
4440  
4441  * The config options listed for this class are options which may appear in each
4442  * individual column definition.
4443  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4444  * @constructor
4445  * @param {Object} config An Array of column config objects. See this class's
4446  * config objects for details.
4447 */
4448 Roo.grid.ColumnModel = function(config){
4449         /**
4450      * The config passed into the constructor
4451      */
4452     this.config = config;
4453     this.lookup = {};
4454
4455     // if no id, create one
4456     // if the column does not have a dataIndex mapping,
4457     // map it to the order it is in the config
4458     for(var i = 0, len = config.length; i < len; i++){
4459         var c = config[i];
4460         if(typeof c.dataIndex == "undefined"){
4461             c.dataIndex = i;
4462         }
4463         if(typeof c.renderer == "string"){
4464             c.renderer = Roo.util.Format[c.renderer];
4465         }
4466         if(typeof c.id == "undefined"){
4467             c.id = Roo.id();
4468         }
4469         if(c.editor && c.editor.xtype){
4470             c.editor  = Roo.factory(c.editor, Roo.grid);
4471         }
4472         if(c.editor && c.editor.isFormField){
4473             c.editor = new Roo.grid.GridEditor(c.editor);
4474         }
4475         this.lookup[c.id] = c;
4476     }
4477
4478     /**
4479      * The width of columns which have no width specified (defaults to 100)
4480      * @type Number
4481      */
4482     this.defaultWidth = 100;
4483
4484     /**
4485      * Default sortable of columns which have no sortable specified (defaults to false)
4486      * @type Boolean
4487      */
4488     this.defaultSortable = false;
4489
4490     this.addEvents({
4491         /**
4492              * @event widthchange
4493              * Fires when the width of a column changes.
4494              * @param {ColumnModel} this
4495              * @param {Number} columnIndex The column index
4496              * @param {Number} newWidth The new width
4497              */
4498             "widthchange": true,
4499         /**
4500              * @event headerchange
4501              * Fires when the text of a header changes.
4502              * @param {ColumnModel} this
4503              * @param {Number} columnIndex The column index
4504              * @param {Number} newText The new header text
4505              */
4506             "headerchange": true,
4507         /**
4508              * @event hiddenchange
4509              * Fires when a column is hidden or "unhidden".
4510              * @param {ColumnModel} this
4511              * @param {Number} columnIndex The column index
4512              * @param {Boolean} hidden true if hidden, false otherwise
4513              */
4514             "hiddenchange": true,
4515             /**
4516          * @event columnmoved
4517          * Fires when a column is moved.
4518          * @param {ColumnModel} this
4519          * @param {Number} oldIndex
4520          * @param {Number} newIndex
4521          */
4522         "columnmoved" : true,
4523         /**
4524          * @event columlockchange
4525          * Fires when a column's locked state is changed
4526          * @param {ColumnModel} this
4527          * @param {Number} colIndex
4528          * @param {Boolean} locked true if locked
4529          */
4530         "columnlockchange" : true
4531     });
4532     Roo.grid.ColumnModel.superclass.constructor.call(this);
4533 };
4534 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4535     /**
4536      * @cfg {String} header The header text to display in the Grid view.
4537      */
4538     /**
4539      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4540      * {@link Roo.data.Record} definition from which to draw the column's value. If not
4541      * specified, the column's index is used as an index into the Record's data Array.
4542      */
4543     /**
4544      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4545      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4546      */
4547     /**
4548      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4549      * Defaults to the value of the {@link #defaultSortable} property.
4550      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4551      */
4552     /**
4553      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
4554      */
4555     /**
4556      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
4557      */
4558     /**
4559      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4560      */
4561     /**
4562      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4563      */
4564     /**
4565      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4566      * given the cell's data value. See {@link #setRenderer}. If not specified, the
4567      * default renderer uses the raw data value. If an object is returned (bootstrap only)
4568      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4569      */
4570        /**
4571      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
4572      */
4573     /**
4574      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
4575      */
4576     /**
4577      * @cfg {String} cursor (Optional)
4578      */
4579     /**
4580      * @cfg {String} tooltip (Optional)
4581      */
4582     /**
4583      * Returns the id of the column at the specified index.
4584      * @param {Number} index The column index
4585      * @return {String} the id
4586      */
4587     getColumnId : function(index){
4588         return this.config[index].id;
4589     },
4590
4591     /**
4592      * Returns the column for a specified id.
4593      * @param {String} id The column id
4594      * @return {Object} the column
4595      */
4596     getColumnById : function(id){
4597         return this.lookup[id];
4598     },
4599
4600     
4601     /**
4602      * Returns the column for a specified dataIndex.
4603      * @param {String} dataIndex The column dataIndex
4604      * @return {Object|Boolean} the column or false if not found
4605      */
4606     getColumnByDataIndex: function(dataIndex){
4607         var index = this.findColumnIndex(dataIndex);
4608         return index > -1 ? this.config[index] : false;
4609     },
4610     
4611     /**
4612      * Returns the index for a specified column id.
4613      * @param {String} id The column id
4614      * @return {Number} the index, or -1 if not found
4615      */
4616     getIndexById : function(id){
4617         for(var i = 0, len = this.config.length; i < len; i++){
4618             if(this.config[i].id == id){
4619                 return i;
4620             }
4621         }
4622         return -1;
4623     },
4624     
4625     /**
4626      * Returns the index for a specified column dataIndex.
4627      * @param {String} dataIndex The column dataIndex
4628      * @return {Number} the index, or -1 if not found
4629      */
4630     
4631     findColumnIndex : function(dataIndex){
4632         for(var i = 0, len = this.config.length; i < len; i++){
4633             if(this.config[i].dataIndex == dataIndex){
4634                 return i;
4635             }
4636         }
4637         return -1;
4638     },
4639     
4640     
4641     moveColumn : function(oldIndex, newIndex){
4642         var c = this.config[oldIndex];
4643         this.config.splice(oldIndex, 1);
4644         this.config.splice(newIndex, 0, c);
4645         this.dataMap = null;
4646         this.fireEvent("columnmoved", this, oldIndex, newIndex);
4647     },
4648
4649     isLocked : function(colIndex){
4650         return this.config[colIndex].locked === true;
4651     },
4652
4653     setLocked : function(colIndex, value, suppressEvent){
4654         if(this.isLocked(colIndex) == value){
4655             return;
4656         }
4657         this.config[colIndex].locked = value;
4658         if(!suppressEvent){
4659             this.fireEvent("columnlockchange", this, colIndex, value);
4660         }
4661     },
4662
4663     getTotalLockedWidth : function(){
4664         var totalWidth = 0;
4665         for(var i = 0; i < this.config.length; i++){
4666             if(this.isLocked(i) && !this.isHidden(i)){
4667                 this.totalWidth += this.getColumnWidth(i);
4668             }
4669         }
4670         return totalWidth;
4671     },
4672
4673     getLockedCount : function(){
4674         for(var i = 0, len = this.config.length; i < len; i++){
4675             if(!this.isLocked(i)){
4676                 return i;
4677             }
4678         }
4679     },
4680
4681     /**
4682      * Returns the number of columns.
4683      * @return {Number}
4684      */
4685     getColumnCount : function(visibleOnly){
4686         if(visibleOnly === true){
4687             var c = 0;
4688             for(var i = 0, len = this.config.length; i < len; i++){
4689                 if(!this.isHidden(i)){
4690                     c++;
4691                 }
4692             }
4693             return c;
4694         }
4695         return this.config.length;
4696     },
4697
4698     /**
4699      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4700      * @param {Function} fn
4701      * @param {Object} scope (optional)
4702      * @return {Array} result
4703      */
4704     getColumnsBy : function(fn, scope){
4705         var r = [];
4706         for(var i = 0, len = this.config.length; i < len; i++){
4707             var c = this.config[i];
4708             if(fn.call(scope||this, c, i) === true){
4709                 r[r.length] = c;
4710             }
4711         }
4712         return r;
4713     },
4714
4715     /**
4716      * Returns true if the specified column is sortable.
4717      * @param {Number} col The column index
4718      * @return {Boolean}
4719      */
4720     isSortable : function(col){
4721         if(typeof this.config[col].sortable == "undefined"){
4722             return this.defaultSortable;
4723         }
4724         return this.config[col].sortable;
4725     },
4726
4727     /**
4728      * Returns the rendering (formatting) function defined for the column.
4729      * @param {Number} col The column index.
4730      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4731      */
4732     getRenderer : function(col){
4733         if(!this.config[col].renderer){
4734             return Roo.grid.ColumnModel.defaultRenderer;
4735         }
4736         return this.config[col].renderer;
4737     },
4738
4739     /**
4740      * Sets the rendering (formatting) function for a column.
4741      * @param {Number} col The column index
4742      * @param {Function} fn The function to use to process the cell's raw data
4743      * to return HTML markup for the grid view. The render function is called with
4744      * the following parameters:<ul>
4745      * <li>Data value.</li>
4746      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4747      * <li>css A CSS style string to apply to the table cell.</li>
4748      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4749      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4750      * <li>Row index</li>
4751      * <li>Column index</li>
4752      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4753      */
4754     setRenderer : function(col, fn){
4755         this.config[col].renderer = fn;
4756     },
4757
4758     /**
4759      * Returns the width for the specified column.
4760      * @param {Number} col The column index
4761      * @return {Number}
4762      */
4763     getColumnWidth : function(col){
4764         return this.config[col].width * 1 || this.defaultWidth;
4765     },
4766
4767     /**
4768      * Sets the width for a column.
4769      * @param {Number} col The column index
4770      * @param {Number} width The new width
4771      */
4772     setColumnWidth : function(col, width, suppressEvent){
4773         this.config[col].width = width;
4774         this.totalWidth = null;
4775         if(!suppressEvent){
4776              this.fireEvent("widthchange", this, col, width);
4777         }
4778     },
4779
4780     /**
4781      * Returns the total width of all columns.
4782      * @param {Boolean} includeHidden True to include hidden column widths
4783      * @return {Number}
4784      */
4785     getTotalWidth : function(includeHidden){
4786         if(!this.totalWidth){
4787             this.totalWidth = 0;
4788             for(var i = 0, len = this.config.length; i < len; i++){
4789                 if(includeHidden || !this.isHidden(i)){
4790                     this.totalWidth += this.getColumnWidth(i);
4791                 }
4792             }
4793         }
4794         return this.totalWidth;
4795     },
4796
4797     /**
4798      * Returns the header for the specified column.
4799      * @param {Number} col The column index
4800      * @return {String}
4801      */
4802     getColumnHeader : function(col){
4803         return this.config[col].header;
4804     },
4805
4806     /**
4807      * Sets the header for a column.
4808      * @param {Number} col The column index
4809      * @param {String} header The new header
4810      */
4811     setColumnHeader : function(col, header){
4812         this.config[col].header = header;
4813         this.fireEvent("headerchange", this, col, header);
4814     },
4815
4816     /**
4817      * Returns the tooltip for the specified column.
4818      * @param {Number} col The column index
4819      * @return {String}
4820      */
4821     getColumnTooltip : function(col){
4822             return this.config[col].tooltip;
4823     },
4824     /**
4825      * Sets the tooltip for a column.
4826      * @param {Number} col The column index
4827      * @param {String} tooltip The new tooltip
4828      */
4829     setColumnTooltip : function(col, tooltip){
4830             this.config[col].tooltip = tooltip;
4831     },
4832
4833     /**
4834      * Returns the dataIndex for the specified column.
4835      * @param {Number} col The column index
4836      * @return {Number}
4837      */
4838     getDataIndex : function(col){
4839         return this.config[col].dataIndex;
4840     },
4841
4842     /**
4843      * Sets the dataIndex for a column.
4844      * @param {Number} col The column index
4845      * @param {Number} dataIndex The new dataIndex
4846      */
4847     setDataIndex : function(col, dataIndex){
4848         this.config[col].dataIndex = dataIndex;
4849     },
4850
4851     
4852     
4853     /**
4854      * Returns true if the cell is editable.
4855      * @param {Number} colIndex The column index
4856      * @param {Number} rowIndex The row index
4857      * @return {Boolean}
4858      */
4859     isCellEditable : function(colIndex, rowIndex){
4860         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4861     },
4862
4863     /**
4864      * Returns the editor defined for the cell/column.
4865      * return false or null to disable editing.
4866      * @param {Number} colIndex The column index
4867      * @param {Number} rowIndex The row index
4868      * @return {Object}
4869      */
4870     getCellEditor : function(colIndex, rowIndex){
4871         return this.config[colIndex].editor;
4872     },
4873
4874     /**
4875      * Sets if a column is editable.
4876      * @param {Number} col The column index
4877      * @param {Boolean} editable True if the column is editable
4878      */
4879     setEditable : function(col, editable){
4880         this.config[col].editable = editable;
4881     },
4882
4883
4884     /**
4885      * Returns true if the column is hidden.
4886      * @param {Number} colIndex The column index
4887      * @return {Boolean}
4888      */
4889     isHidden : function(colIndex){
4890         return this.config[colIndex].hidden;
4891     },
4892
4893
4894     /**
4895      * Returns true if the column width cannot be changed
4896      */
4897     isFixed : function(colIndex){
4898         return this.config[colIndex].fixed;
4899     },
4900
4901     /**
4902      * Returns true if the column can be resized
4903      * @return {Boolean}
4904      */
4905     isResizable : function(colIndex){
4906         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4907     },
4908     /**
4909      * Sets if a column is hidden.
4910      * @param {Number} colIndex The column index
4911      * @param {Boolean} hidden True if the column is hidden
4912      */
4913     setHidden : function(colIndex, hidden){
4914         this.config[colIndex].hidden = hidden;
4915         this.totalWidth = null;
4916         this.fireEvent("hiddenchange", this, colIndex, hidden);
4917     },
4918
4919     /**
4920      * Sets the editor for a column.
4921      * @param {Number} col The column index
4922      * @param {Object} editor The editor object
4923      */
4924     setEditor : function(col, editor){
4925         this.config[col].editor = editor;
4926     }
4927 });
4928
4929 Roo.grid.ColumnModel.defaultRenderer = function(value){
4930         if(typeof value == "string" && value.length < 1){
4931             return "&#160;";
4932         }
4933         return value;
4934 };
4935
4936 // Alias for backwards compatibility
4937 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4938 /*
4939  * Based on:
4940  * Ext JS Library 1.1.1
4941  * Copyright(c) 2006-2007, Ext JS, LLC.
4942  *
4943  * Originally Released Under LGPL - original licence link has changed is not relivant.
4944  *
4945  * Fork - LGPL
4946  * <script type="text/javascript">
4947  */
4948  
4949 /**
4950  * @class Roo.LoadMask
4951  * A simple utility class for generically masking elements while loading data.  If the element being masked has
4952  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4953  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
4954  * element's UpdateManager load indicator and will be destroyed after the initial load.
4955  * @constructor
4956  * Create a new LoadMask
4957  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4958  * @param {Object} config The config object
4959  */
4960 Roo.LoadMask = function(el, config){
4961     this.el = Roo.get(el);
4962     Roo.apply(this, config);
4963     if(this.store){
4964         this.store.on('beforeload', this.onBeforeLoad, this);
4965         this.store.on('load', this.onLoad, this);
4966         this.store.on('loadexception', this.onLoadException, this);
4967         this.removeMask = false;
4968     }else{
4969         var um = this.el.getUpdateManager();
4970         um.showLoadIndicator = false; // disable the default indicator
4971         um.on('beforeupdate', this.onBeforeLoad, this);
4972         um.on('update', this.onLoad, this);
4973         um.on('failure', this.onLoad, this);
4974         this.removeMask = true;
4975     }
4976 };
4977
4978 Roo.LoadMask.prototype = {
4979     /**
4980      * @cfg {Boolean} removeMask
4981      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4982      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
4983      */
4984     /**
4985      * @cfg {String} msg
4986      * The text to display in a centered loading message box (defaults to 'Loading...')
4987      */
4988     msg : 'Loading...',
4989     /**
4990      * @cfg {String} msgCls
4991      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4992      */
4993     msgCls : 'x-mask-loading',
4994
4995     /**
4996      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4997      * @type Boolean
4998      */
4999     disabled: false,
5000
5001     /**
5002      * Disables the mask to prevent it from being displayed
5003      */
5004     disable : function(){
5005        this.disabled = true;
5006     },
5007
5008     /**
5009      * Enables the mask so that it can be displayed
5010      */
5011     enable : function(){
5012         this.disabled = false;
5013     },
5014     
5015     onLoadException : function()
5016     {
5017         Roo.log(arguments);
5018         
5019         if (typeof(arguments[3]) != 'undefined') {
5020             Roo.MessageBox.alert("Error loading",arguments[3]);
5021         } 
5022         /*
5023         try {
5024             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5025                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5026             }   
5027         } catch(e) {
5028             
5029         }
5030         */
5031     
5032         
5033         
5034         this.el.unmask(this.removeMask);
5035     },
5036     // private
5037     onLoad : function()
5038     {
5039         this.el.unmask(this.removeMask);
5040     },
5041
5042     // private
5043     onBeforeLoad : function(){
5044         if(!this.disabled){
5045             this.el.mask(this.msg, this.msgCls);
5046         }
5047     },
5048
5049     // private
5050     destroy : function(){
5051         if(this.store){
5052             this.store.un('beforeload', this.onBeforeLoad, this);
5053             this.store.un('load', this.onLoad, this);
5054             this.store.un('loadexception', this.onLoadException, this);
5055         }else{
5056             var um = this.el.getUpdateManager();
5057             um.un('beforeupdate', this.onBeforeLoad, this);
5058             um.un('update', this.onLoad, this);
5059             um.un('failure', this.onLoad, this);
5060         }
5061     }
5062 };/*
5063  * - LGPL
5064  *
5065  * table
5066  * 
5067  */
5068
5069 /**
5070  * @class Roo.bootstrap.Table
5071  * @extends Roo.bootstrap.Component
5072  * Bootstrap Table class
5073  * @cfg {String} cls table class
5074  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5075  * @cfg {String} bgcolor Specifies the background color for a table
5076  * @cfg {Number} border Specifies whether the table cells should have borders or not
5077  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5078  * @cfg {Number} cellspacing Specifies the space between cells
5079  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5080  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5081  * @cfg {String} sortable Specifies that the table should be sortable
5082  * @cfg {String} summary Specifies a summary of the content of a table
5083  * @cfg {Number} width Specifies the width of a table
5084  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5085  * 
5086  * @cfg {boolean} striped Should the rows be alternative striped
5087  * @cfg {boolean} bordered Add borders to the table
5088  * @cfg {boolean} hover Add hover highlighting
5089  * @cfg {boolean} condensed Format condensed
5090  * @cfg {boolean} responsive Format condensed
5091  * @cfg {Boolean} loadMask (true|false) default false
5092  * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5093  * @cfg {Boolean} thead (true|false) generate thead, default true
5094  * @cfg {Boolean} RowSelection (true|false) default false
5095  * @cfg {Boolean} CellSelection (true|false) default false
5096  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5097  
5098  * 
5099  * @constructor
5100  * Create a new Table
5101  * @param {Object} config The config object
5102  */
5103
5104 Roo.bootstrap.Table = function(config){
5105     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5106     
5107     if (this.sm) {
5108         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5109         this.sm = this.selModel;
5110         this.sm.xmodule = this.xmodule || false;
5111     }
5112     if (this.cm && typeof(this.cm.config) == 'undefined') {
5113         this.colModel = new Roo.grid.ColumnModel(this.cm);
5114         this.cm = this.colModel;
5115         this.cm.xmodule = this.xmodule || false;
5116     }
5117     if (this.store) {
5118         this.store= Roo.factory(this.store, Roo.data);
5119         this.ds = this.store;
5120         this.ds.xmodule = this.xmodule || false;
5121          
5122     }
5123     if (this.footer && this.store) {
5124         this.footer.dataSource = this.ds;
5125         this.footer = Roo.factory(this.footer);
5126     }
5127     
5128     /** @private */
5129     this.addEvents({
5130         /**
5131          * @event cellclick
5132          * Fires when a cell is 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         "cellclick" : true,
5140         /**
5141          * @event celldblclick
5142          * Fires when a cell is double clicked
5143          * @param {Roo.bootstrap.Table} this
5144          * @param {Roo.Element} el
5145          * @param {Number} rowIndex
5146          * @param {Number} columnIndex
5147          * @param {Roo.EventObject} e
5148          */
5149         "celldblclick" : true,
5150         /**
5151          * @event rowclick
5152          * Fires when a row is clicked
5153          * @param {Roo.bootstrap.Table} this
5154          * @param {Roo.Element} el
5155          * @param {Number} rowIndex
5156          * @param {Roo.EventObject} e
5157          */
5158         "rowclick" : true,
5159         /**
5160          * @event rowdblclick
5161          * Fires when a row is double clicked
5162          * @param {Roo.bootstrap.Table} this
5163          * @param {Roo.Element} el
5164          * @param {Number} rowIndex
5165          * @param {Roo.EventObject} e
5166          */
5167         "rowdblclick" : true,
5168         /**
5169          * @event mouseover
5170          * Fires when a mouseover 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         "mouseover" : true,
5178         /**
5179          * @event mouseout
5180          * Fires when a mouseout occur
5181          * @param {Roo.bootstrap.Table} this
5182          * @param {Roo.Element} el
5183          * @param {Number} rowIndex
5184          * @param {Number} columnIndex
5185          * @param {Roo.EventObject} e
5186          */
5187         "mouseout" : true,
5188         /**
5189          * @event rowclass
5190          * Fires when a row is rendered, so you can change add a style to it.
5191          * @param {Roo.bootstrap.Table} this
5192          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5193          */
5194         'rowclass' : true,
5195           /**
5196          * @event rowsrendered
5197          * Fires when all the  rows have been rendered
5198          * @param {Roo.bootstrap.Table} this
5199          */
5200         'rowsrendered' : true
5201         
5202     });
5203 };
5204
5205 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
5206     
5207     cls: false,
5208     align: false,
5209     bgcolor: false,
5210     border: false,
5211     cellpadding: false,
5212     cellspacing: false,
5213     frame: false,
5214     rules: false,
5215     sortable: false,
5216     summary: false,
5217     width: false,
5218     striped : false,
5219     bordered: false,
5220     hover:  false,
5221     condensed : false,
5222     responsive : false,
5223     sm : false,
5224     cm : false,
5225     store : false,
5226     loadMask : false,
5227     tfoot : true,
5228     thead : true,
5229     RowSelection : false,
5230     CellSelection : false,
5231     layout : false,
5232     
5233     // Roo.Element - the tbody
5234     mainBody: false, 
5235     
5236     getAutoCreate : function(){
5237         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5238         
5239         cfg = {
5240             tag: 'table',
5241             cls : 'table',
5242             cn : []
5243         }
5244             
5245         if (this.striped) {
5246             cfg.cls += ' table-striped';
5247         }
5248         
5249         if (this.hover) {
5250             cfg.cls += ' table-hover';
5251         }
5252         if (this.bordered) {
5253             cfg.cls += ' table-bordered';
5254         }
5255         if (this.condensed) {
5256             cfg.cls += ' table-condensed';
5257         }
5258         if (this.responsive) {
5259             cfg.cls += ' table-responsive';
5260         }
5261         
5262         if (this.cls) {
5263             cfg.cls+=  ' ' +this.cls;
5264         }
5265         
5266         // this lot should be simplifed...
5267         
5268         if (this.align) {
5269             cfg.align=this.align;
5270         }
5271         if (this.bgcolor) {
5272             cfg.bgcolor=this.bgcolor;
5273         }
5274         if (this.border) {
5275             cfg.border=this.border;
5276         }
5277         if (this.cellpadding) {
5278             cfg.cellpadding=this.cellpadding;
5279         }
5280         if (this.cellspacing) {
5281             cfg.cellspacing=this.cellspacing;
5282         }
5283         if (this.frame) {
5284             cfg.frame=this.frame;
5285         }
5286         if (this.rules) {
5287             cfg.rules=this.rules;
5288         }
5289         if (this.sortable) {
5290             cfg.sortable=this.sortable;
5291         }
5292         if (this.summary) {
5293             cfg.summary=this.summary;
5294         }
5295         if (this.width) {
5296             cfg.width=this.width;
5297         }
5298         if (this.layout) {
5299             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5300         }
5301         
5302         if(this.store || this.cm){
5303             if(this.thead){
5304                 cfg.cn.push(this.renderHeader());
5305             }
5306             
5307             cfg.cn.push(this.renderBody());
5308             
5309             if(this.tfoot){
5310                 cfg.cn.push(this.renderFooter());
5311             }
5312             
5313             cfg.cls+=  ' TableGrid';
5314         }
5315         
5316         return { cn : [ cfg ] };
5317     },
5318     
5319     initEvents : function()
5320     {   
5321         if(!this.store || !this.cm){
5322             return;
5323         }
5324         
5325         //Roo.log('initEvents with ds!!!!');
5326         
5327         this.mainBody = this.el.select('tbody', true).first();
5328         
5329         
5330         var _this = this;
5331         
5332         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5333             e.on('click', _this.sort, _this);
5334         });
5335         
5336         this.el.on("click", this.onClick, this);
5337         this.el.on("dblclick", this.onDblClick, this);
5338         
5339         // why is this done????? = it breaks dialogs??
5340         //this.parent().el.setStyle('position', 'relative');
5341         
5342         
5343         if (this.footer) {
5344             this.footer.parentId = this.id;
5345             this.footer.onRender(this.el.select('tfoot tr td').first(), null);        
5346         }
5347         
5348         this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5349         
5350         this.store.on('load', this.onLoad, this);
5351         this.store.on('beforeload', this.onBeforeLoad, this);
5352         this.store.on('update', this.onUpdate, this);
5353         this.store.on('add', this.onAdd, this);
5354         
5355     },
5356     
5357     onMouseover : function(e, el)
5358     {
5359         var cell = Roo.get(el);
5360         
5361         if(!cell){
5362             return;
5363         }
5364         
5365         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5366             cell = cell.findParent('td', false, true);
5367         }
5368         
5369         var row = cell.findParent('tr', false, true);
5370         var cellIndex = cell.dom.cellIndex;
5371         var rowIndex = row.dom.rowIndex - 1; // start from 0
5372         
5373         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5374         
5375     },
5376     
5377     onMouseout : function(e, el)
5378     {
5379         var cell = Roo.get(el);
5380         
5381         if(!cell){
5382             return;
5383         }
5384         
5385         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5386             cell = cell.findParent('td', false, true);
5387         }
5388         
5389         var row = cell.findParent('tr', false, true);
5390         var cellIndex = cell.dom.cellIndex;
5391         var rowIndex = row.dom.rowIndex - 1; // start from 0
5392         
5393         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5394         
5395     },
5396     
5397     onClick : function(e, el)
5398     {
5399         var cell = Roo.get(el);
5400         
5401         if(!cell || (!this.CellSelection && !this.RowSelection)){
5402             return;
5403         }
5404         
5405         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5406             cell = cell.findParent('td', false, true);
5407         }
5408         
5409         if(!cell || typeof(cell) == 'undefined'){
5410             return;
5411         }
5412         
5413         var row = cell.findParent('tr', false, true);
5414         
5415         if(!row || typeof(row) == 'undefined'){
5416             return;
5417         }
5418         
5419         var cellIndex = cell.dom.cellIndex;
5420         var rowIndex = this.getRowIndex(row);
5421         
5422         if(this.CellSelection){
5423             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5424         }
5425         
5426         if(this.RowSelection){
5427             this.fireEvent('rowclick', this, row, rowIndex, e);
5428         }
5429         
5430         
5431     },
5432     
5433     onDblClick : function(e,el)
5434     {
5435         var cell = Roo.get(el);
5436         
5437         if(!cell || (!this.CellSelection && !this.RowSelection)){
5438             return;
5439         }
5440         
5441         if(e.getTarget().nodeName.toLowerCase() != 'td'){
5442             cell = cell.findParent('td', false, true);
5443         }
5444         
5445         if(!cell || typeof(cell) == 'undefined'){
5446             return;
5447         }
5448         
5449         var row = cell.findParent('tr', false, true);
5450         
5451         if(!row || typeof(row) == 'undefined'){
5452             return;
5453         }
5454         
5455         var cellIndex = cell.dom.cellIndex;
5456         var rowIndex = this.getRowIndex(row);
5457         
5458         if(this.CellSelection){
5459             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5460         }
5461         
5462         if(this.RowSelection){
5463             this.fireEvent('rowdblclick', this, row, rowIndex, e);
5464         }
5465     },
5466     
5467     sort : function(e,el)
5468     {
5469         var col = Roo.get(el);
5470         
5471         if(!col.hasClass('sortable')){
5472             return;
5473         }
5474         
5475         var sort = col.attr('sort');
5476         var dir = 'ASC';
5477         
5478         if(col.hasClass('glyphicon-arrow-up')){
5479             dir = 'DESC';
5480         }
5481         
5482         this.store.sortInfo = {field : sort, direction : dir};
5483         
5484         if (this.footer) {
5485             Roo.log("calling footer first");
5486             this.footer.onClick('first');
5487         } else {
5488         
5489             this.store.load({ params : { start : 0 } });
5490         }
5491     },
5492     
5493     renderHeader : function()
5494     {
5495         var header = {
5496             tag: 'thead',
5497             cn : []
5498         };
5499         
5500         var cm = this.cm;
5501         
5502         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5503             
5504             var config = cm.config[i];
5505                     
5506             var c = {
5507                 tag: 'th',
5508                 style : '',
5509                 html: cm.getColumnHeader(i)
5510             };
5511             
5512             if(typeof(config.tooltip) != 'undefined'){
5513                 c.tooltip = config.tooltip;
5514             }
5515             
5516             if(typeof(config.colspan) != 'undefined'){
5517                 c.colspan = config.colspan;
5518             }
5519             
5520             if(typeof(config.hidden) != 'undefined' && config.hidden){
5521                 c.style += ' display:none;';
5522             }
5523             
5524             if(typeof(config.dataIndex) != 'undefined'){
5525                 c.sort = config.dataIndex;
5526             }
5527             
5528             if(typeof(config.sortable) != 'undefined' && config.sortable){
5529                 c.cls = 'sortable';
5530             }
5531             
5532             if(typeof(config.align) != 'undefined' && config.align.length){
5533                 c.style += ' text-align:' + config.align + ';';
5534             }
5535             
5536             if(typeof(config.width) != 'undefined'){
5537                 c.style += ' width:' + config.width + 'px;';
5538             }
5539             
5540             header.cn.push(c)
5541         }
5542         
5543         return header;
5544     },
5545     
5546     renderBody : function()
5547     {
5548         var body = {
5549             tag: 'tbody',
5550             cn : [
5551                 {
5552                     tag: 'tr',
5553                     cn : [
5554                         {
5555                             tag : 'td',
5556                             colspan :  this.cm.getColumnCount()
5557                         }
5558                     ]
5559                 }
5560             ]
5561         };
5562         
5563         return body;
5564     },
5565     
5566     renderFooter : function()
5567     {
5568         var footer = {
5569             tag: 'tfoot',
5570             cn : [
5571                 {
5572                     tag: 'tr',
5573                     cn : [
5574                         {
5575                             tag : 'td',
5576                             colspan :  this.cm.getColumnCount()
5577                         }
5578                     ]
5579                 }
5580             ]
5581         };
5582         
5583         return footer;
5584     },
5585     
5586     
5587     
5588     onLoad : function()
5589     {
5590         Roo.log('ds onload');
5591         this.clear();
5592         
5593         var _this = this;
5594         var cm = this.cm;
5595         var ds = this.store;
5596         
5597         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5598             e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5599             
5600             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5601                 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5602             }
5603             
5604             if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5605                 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5606             }
5607         });
5608         
5609         var tbody =  this.mainBody;
5610               
5611         if(ds.getCount() > 0){
5612             ds.data.each(function(d,rowIndex){
5613                 var row =  this.renderRow(cm, ds, rowIndex);
5614                 
5615                 tbody.createChild(row);
5616                 
5617                 var _this = this;
5618                 
5619                 if(row.cellObjects.length){
5620                     Roo.each(row.cellObjects, function(r){
5621                         _this.renderCellObject(r);
5622                     })
5623                 }
5624                 
5625             }, this);
5626         }
5627         
5628         Roo.each(this.el.select('tbody td', true).elements, function(e){
5629             e.on('mouseover', _this.onMouseover, _this);
5630         });
5631         
5632         Roo.each(this.el.select('tbody td', true).elements, function(e){
5633             e.on('mouseout', _this.onMouseout, _this);
5634         });
5635         this.fireEvent('rowsrendered', this);
5636         //if(this.loadMask){
5637         //    this.maskEl.hide();
5638         //}
5639     },
5640     
5641     
5642     onUpdate : function(ds,record)
5643     {
5644         this.refreshRow(record);
5645     },
5646     
5647     onRemove : function(ds, record, index, isUpdate){
5648         if(isUpdate !== true){
5649             this.fireEvent("beforerowremoved", this, index, record);
5650         }
5651         var bt = this.mainBody.dom;
5652         
5653         var rows = this.el.select('tbody > tr', true).elements;
5654         
5655         if(typeof(rows[index]) != 'undefined'){
5656             bt.removeChild(rows[index].dom);
5657         }
5658         
5659 //        if(bt.rows[index]){
5660 //            bt.removeChild(bt.rows[index]);
5661 //        }
5662         
5663         if(isUpdate !== true){
5664             //this.stripeRows(index);
5665             //this.syncRowHeights(index, index);
5666             //this.layout();
5667             this.fireEvent("rowremoved", this, index, record);
5668         }
5669     },
5670     
5671     onAdd : function(ds, records, rowIndex)
5672     {
5673         //Roo.log('on Add called');
5674         // - note this does not handle multiple adding very well..
5675         var bt = this.mainBody.dom;
5676         for (var i =0 ; i < records.length;i++) {
5677             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5678             //Roo.log(records[i]);
5679             //Roo.log(this.store.getAt(rowIndex+i));
5680             this.insertRow(this.store, rowIndex + i, false);
5681             return;
5682         }
5683         
5684     },
5685     
5686     
5687     refreshRow : function(record){
5688         var ds = this.store, index;
5689         if(typeof record == 'number'){
5690             index = record;
5691             record = ds.getAt(index);
5692         }else{
5693             index = ds.indexOf(record);
5694         }
5695         this.insertRow(ds, index, true);
5696         this.onRemove(ds, record, index+1, true);
5697         //this.syncRowHeights(index, index);
5698         //this.layout();
5699         this.fireEvent("rowupdated", this, index, record);
5700     },
5701     
5702     insertRow : function(dm, rowIndex, isUpdate){
5703         
5704         if(!isUpdate){
5705             this.fireEvent("beforerowsinserted", this, rowIndex);
5706         }
5707             //var s = this.getScrollState();
5708         var row = this.renderRow(this.cm, this.store, rowIndex);
5709         // insert before rowIndex..
5710         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5711         
5712         var _this = this;
5713                 
5714         if(row.cellObjects.length){
5715             Roo.each(row.cellObjects, function(r){
5716                 _this.renderCellObject(r);
5717             })
5718         }
5719             
5720         if(!isUpdate){
5721             this.fireEvent("rowsinserted", this, rowIndex);
5722             //this.syncRowHeights(firstRow, lastRow);
5723             //this.stripeRows(firstRow);
5724             //this.layout();
5725         }
5726         
5727     },
5728     
5729     
5730     getRowDom : function(rowIndex)
5731     {
5732         var rows = this.el.select('tbody > tr', true).elements;
5733         
5734         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5735         
5736     },
5737     // returns the object tree for a tr..
5738   
5739     
5740     renderRow : function(cm, ds, rowIndex) 
5741     {
5742         
5743         var d = ds.getAt(rowIndex);
5744         
5745         var row = {
5746             tag : 'tr',
5747             cn : []
5748         };
5749             
5750         var cellObjects = [];
5751         
5752         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5753             var config = cm.config[i];
5754             
5755             var renderer = cm.getRenderer(i);
5756             var value = '';
5757             var id = false;
5758             
5759             if(typeof(renderer) !== 'undefined'){
5760                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5761             }
5762             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5763             // and are rendered into the cells after the row is rendered - using the id for the element.
5764             
5765             if(typeof(value) === 'object'){
5766                 id = Roo.id();
5767                 cellObjects.push({
5768                     container : id,
5769                     cfg : value 
5770                 })
5771             }
5772             
5773             var rowcfg = {
5774                 record: d,
5775                 rowIndex : rowIndex,
5776                 colIndex : i,
5777                 rowClass : ''
5778             }
5779
5780             this.fireEvent('rowclass', this, rowcfg);
5781             
5782             var td = {
5783                 tag: 'td',
5784                 cls : rowcfg.rowClass,
5785                 style: '',
5786                 html: (typeof(value) === 'object') ? '' : value
5787             };
5788             
5789             if (id) {
5790                 td.id = id;
5791             }
5792             
5793             if(typeof(config.colspan) != 'undefined'){
5794                 td.colspan = config.colspan;
5795             }
5796             
5797             if(typeof(config.hidden) != 'undefined' && config.hidden){
5798                 td.style += ' display:none;';
5799             }
5800             
5801             if(typeof(config.align) != 'undefined' && config.align.length){
5802                 td.style += ' text-align:' + config.align + ';';
5803             }
5804             
5805             if(typeof(config.width) != 'undefined'){
5806                 td.style += ' width:' +  config.width + 'px;';
5807             }
5808             
5809             if(typeof(config.cursor) != 'undefined'){
5810                 td.style += ' cursor:' +  config.cursor + ';';
5811             }
5812              
5813             row.cn.push(td);
5814            
5815         }
5816         
5817         row.cellObjects = cellObjects;
5818         
5819         return row;
5820           
5821     },
5822     
5823     
5824     
5825     onBeforeLoad : function()
5826     {
5827         //Roo.log('ds onBeforeLoad');
5828         
5829         //this.clear();
5830         
5831         //if(this.loadMask){
5832         //    this.maskEl.show();
5833         //}
5834     },
5835      /**
5836      * Remove all rows
5837      */
5838     clear : function()
5839     {
5840         this.el.select('tbody', true).first().dom.innerHTML = '';
5841     },
5842     /**
5843      * Show or hide a row.
5844      * @param {Number} rowIndex to show or hide
5845      * @param {Boolean} state hide
5846      */
5847     setRowVisibility : function(rowIndex, state)
5848     {
5849         var bt = this.mainBody.dom;
5850         
5851         var rows = this.el.select('tbody > tr', true).elements;
5852         
5853         if(typeof(rows[rowIndex]) == 'undefined'){
5854             return;
5855         }
5856         rows[rowIndex].dom.style.display = state ? '' : 'none';
5857     },
5858     
5859     
5860     getSelectionModel : function(){
5861         if(!this.selModel){
5862             this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5863         }
5864         return this.selModel;
5865     },
5866     /*
5867      * Render the Roo.bootstrap object from renderder
5868      */
5869     renderCellObject : function(r)
5870     {
5871         var _this = this;
5872         
5873         var t = r.cfg.render(r.container);
5874         
5875         if(r.cfg.cn){
5876             Roo.each(r.cfg.cn, function(c){
5877                 var child = {
5878                     container: t.getChildContainer(),
5879                     cfg: c
5880                 }
5881                 _this.renderCellObject(child);
5882             })
5883         }
5884     },
5885     
5886     getRowIndex : function(row)
5887     {
5888         var rowIndex = -1;
5889         
5890         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
5891             if(el != row){
5892                 return;
5893             }
5894             
5895             rowIndex = index;
5896         });
5897         
5898         return rowIndex;
5899     }
5900    
5901 });
5902
5903  
5904
5905  /*
5906  * - LGPL
5907  *
5908  * table cell
5909  * 
5910  */
5911
5912 /**
5913  * @class Roo.bootstrap.TableCell
5914  * @extends Roo.bootstrap.Component
5915  * Bootstrap TableCell class
5916  * @cfg {String} html cell contain text
5917  * @cfg {String} cls cell class
5918  * @cfg {String} tag cell tag (td|th) default td
5919  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5920  * @cfg {String} align Aligns the content in a cell
5921  * @cfg {String} axis Categorizes cells
5922  * @cfg {String} bgcolor Specifies the background color of a cell
5923  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5924  * @cfg {Number} colspan Specifies the number of columns a cell should span
5925  * @cfg {String} headers Specifies one or more header cells a cell is related to
5926  * @cfg {Number} height Sets the height of a cell
5927  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5928  * @cfg {Number} rowspan Sets the number of rows a cell should span
5929  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5930  * @cfg {String} valign Vertical aligns the content in a cell
5931  * @cfg {Number} width Specifies the width of a cell
5932  * 
5933  * @constructor
5934  * Create a new TableCell
5935  * @param {Object} config The config object
5936  */
5937
5938 Roo.bootstrap.TableCell = function(config){
5939     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5940 };
5941
5942 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
5943     
5944     html: false,
5945     cls: false,
5946     tag: false,
5947     abbr: false,
5948     align: false,
5949     axis: false,
5950     bgcolor: false,
5951     charoff: false,
5952     colspan: false,
5953     headers: false,
5954     height: false,
5955     nowrap: false,
5956     rowspan: false,
5957     scope: false,
5958     valign: false,
5959     width: false,
5960     
5961     
5962     getAutoCreate : function(){
5963         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5964         
5965         cfg = {
5966             tag: 'td'
5967         }
5968         
5969         if(this.tag){
5970             cfg.tag = this.tag;
5971         }
5972         
5973         if (this.html) {
5974             cfg.html=this.html
5975         }
5976         if (this.cls) {
5977             cfg.cls=this.cls
5978         }
5979         if (this.abbr) {
5980             cfg.abbr=this.abbr
5981         }
5982         if (this.align) {
5983             cfg.align=this.align
5984         }
5985         if (this.axis) {
5986             cfg.axis=this.axis
5987         }
5988         if (this.bgcolor) {
5989             cfg.bgcolor=this.bgcolor
5990         }
5991         if (this.charoff) {
5992             cfg.charoff=this.charoff
5993         }
5994         if (this.colspan) {
5995             cfg.colspan=this.colspan
5996         }
5997         if (this.headers) {
5998             cfg.headers=this.headers
5999         }
6000         if (this.height) {
6001             cfg.height=this.height
6002         }
6003         if (this.nowrap) {
6004             cfg.nowrap=this.nowrap
6005         }
6006         if (this.rowspan) {
6007             cfg.rowspan=this.rowspan
6008         }
6009         if (this.scope) {
6010             cfg.scope=this.scope
6011         }
6012         if (this.valign) {
6013             cfg.valign=this.valign
6014         }
6015         if (this.width) {
6016             cfg.width=this.width
6017         }
6018         
6019         
6020         return cfg;
6021     }
6022    
6023 });
6024
6025  
6026
6027  /*
6028  * - LGPL
6029  *
6030  * table row
6031  * 
6032  */
6033
6034 /**
6035  * @class Roo.bootstrap.TableRow
6036  * @extends Roo.bootstrap.Component
6037  * Bootstrap TableRow class
6038  * @cfg {String} cls row class
6039  * @cfg {String} align Aligns the content in a table row
6040  * @cfg {String} bgcolor Specifies a background color for a table row
6041  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6042  * @cfg {String} valign Vertical aligns the content in a table row
6043  * 
6044  * @constructor
6045  * Create a new TableRow
6046  * @param {Object} config The config object
6047  */
6048
6049 Roo.bootstrap.TableRow = function(config){
6050     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6051 };
6052
6053 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
6054     
6055     cls: false,
6056     align: false,
6057     bgcolor: false,
6058     charoff: false,
6059     valign: false,
6060     
6061     getAutoCreate : function(){
6062         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6063         
6064         cfg = {
6065             tag: 'tr'
6066         }
6067             
6068         if(this.cls){
6069             cfg.cls = this.cls;
6070         }
6071         if(this.align){
6072             cfg.align = this.align;
6073         }
6074         if(this.bgcolor){
6075             cfg.bgcolor = this.bgcolor;
6076         }
6077         if(this.charoff){
6078             cfg.charoff = this.charoff;
6079         }
6080         if(this.valign){
6081             cfg.valign = this.valign;
6082         }
6083         
6084         return cfg;
6085     }
6086    
6087 });
6088
6089  
6090
6091  /*
6092  * - LGPL
6093  *
6094  * table body
6095  * 
6096  */
6097
6098 /**
6099  * @class Roo.bootstrap.TableBody
6100  * @extends Roo.bootstrap.Component
6101  * Bootstrap TableBody class
6102  * @cfg {String} cls element class
6103  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6104  * @cfg {String} align Aligns the content inside the element
6105  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6106  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6107  * 
6108  * @constructor
6109  * Create a new TableBody
6110  * @param {Object} config The config object
6111  */
6112
6113 Roo.bootstrap.TableBody = function(config){
6114     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6115 };
6116
6117 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
6118     
6119     cls: false,
6120     tag: false,
6121     align: false,
6122     charoff: false,
6123     valign: false,
6124     
6125     getAutoCreate : function(){
6126         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6127         
6128         cfg = {
6129             tag: 'tbody'
6130         }
6131             
6132         if (this.cls) {
6133             cfg.cls=this.cls
6134         }
6135         if(this.tag){
6136             cfg.tag = this.tag;
6137         }
6138         
6139         if(this.align){
6140             cfg.align = this.align;
6141         }
6142         if(this.charoff){
6143             cfg.charoff = this.charoff;
6144         }
6145         if(this.valign){
6146             cfg.valign = this.valign;
6147         }
6148         
6149         return cfg;
6150     }
6151     
6152     
6153 //    initEvents : function()
6154 //    {
6155 //        
6156 //        if(!this.store){
6157 //            return;
6158 //        }
6159 //        
6160 //        this.store = Roo.factory(this.store, Roo.data);
6161 //        this.store.on('load', this.onLoad, this);
6162 //        
6163 //        this.store.load();
6164 //        
6165 //    },
6166 //    
6167 //    onLoad: function () 
6168 //    {   
6169 //        this.fireEvent('load', this);
6170 //    }
6171 //    
6172 //   
6173 });
6174
6175  
6176
6177  /*
6178  * Based on:
6179  * Ext JS Library 1.1.1
6180  * Copyright(c) 2006-2007, Ext JS, LLC.
6181  *
6182  * Originally Released Under LGPL - original licence link has changed is not relivant.
6183  *
6184  * Fork - LGPL
6185  * <script type="text/javascript">
6186  */
6187
6188 // as we use this in bootstrap.
6189 Roo.namespace('Roo.form');
6190  /**
6191  * @class Roo.form.Action
6192  * Internal Class used to handle form actions
6193  * @constructor
6194  * @param {Roo.form.BasicForm} el The form element or its id
6195  * @param {Object} config Configuration options
6196  */
6197
6198  
6199  
6200 // define the action interface
6201 Roo.form.Action = function(form, options){
6202     this.form = form;
6203     this.options = options || {};
6204 };
6205 /**
6206  * Client Validation Failed
6207  * @const 
6208  */
6209 Roo.form.Action.CLIENT_INVALID = 'client';
6210 /**
6211  * Server Validation Failed
6212  * @const 
6213  */
6214 Roo.form.Action.SERVER_INVALID = 'server';
6215  /**
6216  * Connect to Server Failed
6217  * @const 
6218  */
6219 Roo.form.Action.CONNECT_FAILURE = 'connect';
6220 /**
6221  * Reading Data from Server Failed
6222  * @const 
6223  */
6224 Roo.form.Action.LOAD_FAILURE = 'load';
6225
6226 Roo.form.Action.prototype = {
6227     type : 'default',
6228     failureType : undefined,
6229     response : undefined,
6230     result : undefined,
6231
6232     // interface method
6233     run : function(options){
6234
6235     },
6236
6237     // interface method
6238     success : function(response){
6239
6240     },
6241
6242     // interface method
6243     handleResponse : function(response){
6244
6245     },
6246
6247     // default connection failure
6248     failure : function(response){
6249         
6250         this.response = response;
6251         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6252         this.form.afterAction(this, false);
6253     },
6254
6255     processResponse : function(response){
6256         this.response = response;
6257         if(!response.responseText){
6258             return true;
6259         }
6260         this.result = this.handleResponse(response);
6261         return this.result;
6262     },
6263
6264     // utility functions used internally
6265     getUrl : function(appendParams){
6266         var url = this.options.url || this.form.url || this.form.el.dom.action;
6267         if(appendParams){
6268             var p = this.getParams();
6269             if(p){
6270                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6271             }
6272         }
6273         return url;
6274     },
6275
6276     getMethod : function(){
6277         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6278     },
6279
6280     getParams : function(){
6281         var bp = this.form.baseParams;
6282         var p = this.options.params;
6283         if(p){
6284             if(typeof p == "object"){
6285                 p = Roo.urlEncode(Roo.applyIf(p, bp));
6286             }else if(typeof p == 'string' && bp){
6287                 p += '&' + Roo.urlEncode(bp);
6288             }
6289         }else if(bp){
6290             p = Roo.urlEncode(bp);
6291         }
6292         return p;
6293     },
6294
6295     createCallback : function(){
6296         return {
6297             success: this.success,
6298             failure: this.failure,
6299             scope: this,
6300             timeout: (this.form.timeout*1000),
6301             upload: this.form.fileUpload ? this.success : undefined
6302         };
6303     }
6304 };
6305
6306 Roo.form.Action.Submit = function(form, options){
6307     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6308 };
6309
6310 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6311     type : 'submit',
6312
6313     haveProgress : false,
6314     uploadComplete : false,
6315     
6316     // uploadProgress indicator.
6317     uploadProgress : function()
6318     {
6319         if (!this.form.progressUrl) {
6320             return;
6321         }
6322         
6323         if (!this.haveProgress) {
6324             Roo.MessageBox.progress("Uploading", "Uploading");
6325         }
6326         if (this.uploadComplete) {
6327            Roo.MessageBox.hide();
6328            return;
6329         }
6330         
6331         this.haveProgress = true;
6332    
6333         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6334         
6335         var c = new Roo.data.Connection();
6336         c.request({
6337             url : this.form.progressUrl,
6338             params: {
6339                 id : uid
6340             },
6341             method: 'GET',
6342             success : function(req){
6343                //console.log(data);
6344                 var rdata = false;
6345                 var edata;
6346                 try  {
6347                    rdata = Roo.decode(req.responseText)
6348                 } catch (e) {
6349                     Roo.log("Invalid data from server..");
6350                     Roo.log(edata);
6351                     return;
6352                 }
6353                 if (!rdata || !rdata.success) {
6354                     Roo.log(rdata);
6355                     Roo.MessageBox.alert(Roo.encode(rdata));
6356                     return;
6357                 }
6358                 var data = rdata.data;
6359                 
6360                 if (this.uploadComplete) {
6361                    Roo.MessageBox.hide();
6362                    return;
6363                 }
6364                    
6365                 if (data){
6366                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6367                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6368                     );
6369                 }
6370                 this.uploadProgress.defer(2000,this);
6371             },
6372        
6373             failure: function(data) {
6374                 Roo.log('progress url failed ');
6375                 Roo.log(data);
6376             },
6377             scope : this
6378         });
6379            
6380     },
6381     
6382     
6383     run : function()
6384     {
6385         // run get Values on the form, so it syncs any secondary forms.
6386         this.form.getValues();
6387         
6388         var o = this.options;
6389         var method = this.getMethod();
6390         var isPost = method == 'POST';
6391         if(o.clientValidation === false || this.form.isValid()){
6392             
6393             if (this.form.progressUrl) {
6394                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6395                     (new Date() * 1) + '' + Math.random());
6396                     
6397             } 
6398             
6399             
6400             Roo.Ajax.request(Roo.apply(this.createCallback(), {
6401                 form:this.form.el.dom,
6402                 url:this.getUrl(!isPost),
6403                 method: method,
6404                 params:isPost ? this.getParams() : null,
6405                 isUpload: this.form.fileUpload
6406             }));
6407             
6408             this.uploadProgress();
6409
6410         }else if (o.clientValidation !== false){ // client validation failed
6411             this.failureType = Roo.form.Action.CLIENT_INVALID;
6412             this.form.afterAction(this, false);
6413         }
6414     },
6415
6416     success : function(response)
6417     {
6418         this.uploadComplete= true;
6419         if (this.haveProgress) {
6420             Roo.MessageBox.hide();
6421         }
6422         
6423         
6424         var result = this.processResponse(response);
6425         if(result === true || result.success){
6426             this.form.afterAction(this, true);
6427             return;
6428         }
6429         if(result.errors){
6430             this.form.markInvalid(result.errors);
6431             this.failureType = Roo.form.Action.SERVER_INVALID;
6432         }
6433         this.form.afterAction(this, false);
6434     },
6435     failure : function(response)
6436     {
6437         this.uploadComplete= true;
6438         if (this.haveProgress) {
6439             Roo.MessageBox.hide();
6440         }
6441         
6442         this.response = response;
6443         this.failureType = Roo.form.Action.CONNECT_FAILURE;
6444         this.form.afterAction(this, false);
6445     },
6446     
6447     handleResponse : function(response){
6448         if(this.form.errorReader){
6449             var rs = this.form.errorReader.read(response);
6450             var errors = [];
6451             if(rs.records){
6452                 for(var i = 0, len = rs.records.length; i < len; i++) {
6453                     var r = rs.records[i];
6454                     errors[i] = r.data;
6455                 }
6456             }
6457             if(errors.length < 1){
6458                 errors = null;
6459             }
6460             return {
6461                 success : rs.success,
6462                 errors : errors
6463             };
6464         }
6465         var ret = false;
6466         try {
6467             ret = Roo.decode(response.responseText);
6468         } catch (e) {
6469             ret = {
6470                 success: false,
6471                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6472                 errors : []
6473             };
6474         }
6475         return ret;
6476         
6477     }
6478 });
6479
6480
6481 Roo.form.Action.Load = function(form, options){
6482     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6483     this.reader = this.form.reader;
6484 };
6485
6486 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6487     type : 'load',
6488
6489     run : function(){
6490         
6491         Roo.Ajax.request(Roo.apply(
6492                 this.createCallback(), {
6493                     method:this.getMethod(),
6494                     url:this.getUrl(false),
6495                     params:this.getParams()
6496         }));
6497     },
6498
6499     success : function(response){
6500         
6501         var result = this.processResponse(response);
6502         if(result === true || !result.success || !result.data){
6503             this.failureType = Roo.form.Action.LOAD_FAILURE;
6504             this.form.afterAction(this, false);
6505             return;
6506         }
6507         this.form.clearInvalid();
6508         this.form.setValues(result.data);
6509         this.form.afterAction(this, true);
6510     },
6511
6512     handleResponse : function(response){
6513         if(this.form.reader){
6514             var rs = this.form.reader.read(response);
6515             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6516             return {
6517                 success : rs.success,
6518                 data : data
6519             };
6520         }
6521         return Roo.decode(response.responseText);
6522     }
6523 });
6524
6525 Roo.form.Action.ACTION_TYPES = {
6526     'load' : Roo.form.Action.Load,
6527     'submit' : Roo.form.Action.Submit
6528 };/*
6529  * - LGPL
6530  *
6531  * form
6532  * 
6533  */
6534
6535 /**
6536  * @class Roo.bootstrap.Form
6537  * @extends Roo.bootstrap.Component
6538  * Bootstrap Form class
6539  * @cfg {String} method  GET | POST (default POST)
6540  * @cfg {String} labelAlign top | left (default top)
6541  * @cfg {String} align left  | right - for navbars
6542  * @cfg {Boolean} loadMask load mask when submit (default true)
6543
6544  * 
6545  * @constructor
6546  * Create a new Form
6547  * @param {Object} config The config object
6548  */
6549
6550
6551 Roo.bootstrap.Form = function(config){
6552     Roo.bootstrap.Form.superclass.constructor.call(this, config);
6553     this.addEvents({
6554         /**
6555          * @event clientvalidation
6556          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6557          * @param {Form} this
6558          * @param {Boolean} valid true if the form has passed client-side validation
6559          */
6560         clientvalidation: true,
6561         /**
6562          * @event beforeaction
6563          * Fires before any action is performed. Return false to cancel the action.
6564          * @param {Form} this
6565          * @param {Action} action The action to be performed
6566          */
6567         beforeaction: true,
6568         /**
6569          * @event actionfailed
6570          * Fires when an action fails.
6571          * @param {Form} this
6572          * @param {Action} action The action that failed
6573          */
6574         actionfailed : true,
6575         /**
6576          * @event actioncomplete
6577          * Fires when an action is completed.
6578          * @param {Form} this
6579          * @param {Action} action The action that completed
6580          */
6581         actioncomplete : true
6582     });
6583     
6584 };
6585
6586 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
6587       
6588      /**
6589      * @cfg {String} method
6590      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6591      */
6592     method : 'POST',
6593     /**
6594      * @cfg {String} url
6595      * The URL to use for form actions if one isn't supplied in the action options.
6596      */
6597     /**
6598      * @cfg {Boolean} fileUpload
6599      * Set to true if this form is a file upload.
6600      */
6601      
6602     /**
6603      * @cfg {Object} baseParams
6604      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6605      */
6606       
6607     /**
6608      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6609      */
6610     timeout: 30,
6611     /**
6612      * @cfg {Sting} align (left|right) for navbar forms
6613      */
6614     align : 'left',
6615
6616     // private
6617     activeAction : null,
6618  
6619     /**
6620      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6621      * element by passing it or its id or mask the form itself by passing in true.
6622      * @type Mixed
6623      */
6624     waitMsgTarget : false,
6625     
6626     loadMask : true,
6627     
6628     getAutoCreate : function(){
6629         
6630         var cfg = {
6631             tag: 'form',
6632             method : this.method || 'POST',
6633             id : this.id || Roo.id(),
6634             cls : ''
6635         }
6636         if (this.parent().xtype.match(/^Nav/)) {
6637             cfg.cls = 'navbar-form navbar-' + this.align;
6638             
6639         }
6640         
6641         if (this.labelAlign == 'left' ) {
6642             cfg.cls += ' form-horizontal';
6643         }
6644         
6645         
6646         return cfg;
6647     },
6648     initEvents : function()
6649     {
6650         this.el.on('submit', this.onSubmit, this);
6651         // this was added as random key presses on the form where triggering form submit.
6652         this.el.on('keypress', function(e) {
6653             if (e.getCharCode() != 13) {
6654                 return true;
6655             }
6656             // we might need to allow it for textareas.. and some other items.
6657             // check e.getTarget().
6658             
6659             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6660                 return true;
6661             }
6662         
6663             Roo.log("keypress blocked");
6664             
6665             e.preventDefault();
6666             return false;
6667         });
6668         
6669     },
6670     // private
6671     onSubmit : function(e){
6672         e.stopEvent();
6673     },
6674     
6675      /**
6676      * Returns true if client-side validation on the form is successful.
6677      * @return Boolean
6678      */
6679     isValid : function(){
6680         var items = this.getItems();
6681         var valid = true;
6682         items.each(function(f){
6683            if(!f.validate()){
6684                valid = false;
6685                
6686            }
6687         });
6688         return valid;
6689     },
6690     /**
6691      * Returns true if any fields in this form have changed since their original load.
6692      * @return Boolean
6693      */
6694     isDirty : function(){
6695         var dirty = false;
6696         var items = this.getItems();
6697         items.each(function(f){
6698            if(f.isDirty()){
6699                dirty = true;
6700                return false;
6701            }
6702            return true;
6703         });
6704         return dirty;
6705     },
6706      /**
6707      * Performs a predefined action (submit or load) or custom actions you define on this form.
6708      * @param {String} actionName The name of the action type
6709      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
6710      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6711      * accept other config options):
6712      * <pre>
6713 Property          Type             Description
6714 ----------------  ---------------  ----------------------------------------------------------------------------------
6715 url               String           The url for the action (defaults to the form's url)
6716 method            String           The form method to use (defaults to the form's method, or POST if not defined)
6717 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
6718 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
6719                                    validate the form on the client (defaults to false)
6720      * </pre>
6721      * @return {BasicForm} this
6722      */
6723     doAction : function(action, options){
6724         if(typeof action == 'string'){
6725             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6726         }
6727         if(this.fireEvent('beforeaction', this, action) !== false){
6728             this.beforeAction(action);
6729             action.run.defer(100, action);
6730         }
6731         return this;
6732     },
6733     
6734     // private
6735     beforeAction : function(action){
6736         var o = action.options;
6737         
6738         if(this.loadMask){
6739             this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6740         }
6741         // not really supported yet.. ??
6742         
6743         //if(this.waitMsgTarget === true){
6744         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6745         //}else if(this.waitMsgTarget){
6746         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6747         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6748         //}else {
6749         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6750        // }
6751          
6752     },
6753
6754     // private
6755     afterAction : function(action, success){
6756         this.activeAction = null;
6757         var o = action.options;
6758         
6759         //if(this.waitMsgTarget === true){
6760             this.el.unmask();
6761         //}else if(this.waitMsgTarget){
6762         //    this.waitMsgTarget.unmask();
6763         //}else{
6764         //    Roo.MessageBox.updateProgress(1);
6765         //    Roo.MessageBox.hide();
6766        // }
6767         // 
6768         if(success){
6769             if(o.reset){
6770                 this.reset();
6771             }
6772             Roo.callback(o.success, o.scope, [this, action]);
6773             this.fireEvent('actioncomplete', this, action);
6774             
6775         }else{
6776             
6777             // failure condition..
6778             // we have a scenario where updates need confirming.
6779             // eg. if a locking scenario exists..
6780             // we look for { errors : { needs_confirm : true }} in the response.
6781             if (
6782                 (typeof(action.result) != 'undefined')  &&
6783                 (typeof(action.result.errors) != 'undefined')  &&
6784                 (typeof(action.result.errors.needs_confirm) != 'undefined')
6785            ){
6786                 var _t = this;
6787                 Roo.log("not supported yet");
6788                  /*
6789                 
6790                 Roo.MessageBox.confirm(
6791                     "Change requires confirmation",
6792                     action.result.errorMsg,
6793                     function(r) {
6794                         if (r != 'yes') {
6795                             return;
6796                         }
6797                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
6798                     }
6799                     
6800                 );
6801                 */
6802                 
6803                 
6804                 return;
6805             }
6806             
6807             Roo.callback(o.failure, o.scope, [this, action]);
6808             // show an error message if no failed handler is set..
6809             if (!this.hasListener('actionfailed')) {
6810                 Roo.log("need to add dialog support");
6811                 /*
6812                 Roo.MessageBox.alert("Error",
6813                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6814                         action.result.errorMsg :
6815                         "Saving Failed, please check your entries or try again"
6816                 );
6817                 */
6818             }
6819             
6820             this.fireEvent('actionfailed', this, action);
6821         }
6822         
6823     },
6824     /**
6825      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
6826      * @param {String} id The value to search for
6827      * @return Field
6828      */
6829     findField : function(id){
6830         var items = this.getItems();
6831         var field = items.get(id);
6832         if(!field){
6833              items.each(function(f){
6834                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
6835                     field = f;
6836                     return false;
6837                 }
6838                 return true;
6839             });
6840         }
6841         return field || null;
6842     },
6843      /**
6844      * Mark fields in this form invalid in bulk.
6845      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
6846      * @return {BasicForm} this
6847      */
6848     markInvalid : function(errors){
6849         if(errors instanceof Array){
6850             for(var i = 0, len = errors.length; i < len; i++){
6851                 var fieldError = errors[i];
6852                 var f = this.findField(fieldError.id);
6853                 if(f){
6854                     f.markInvalid(fieldError.msg);
6855                 }
6856             }
6857         }else{
6858             var field, id;
6859             for(id in errors){
6860                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6861                     field.markInvalid(errors[id]);
6862                 }
6863             }
6864         }
6865         //Roo.each(this.childForms || [], function (f) {
6866         //    f.markInvalid(errors);
6867         //});
6868         
6869         return this;
6870     },
6871
6872     /**
6873      * Set values for fields in this form in bulk.
6874      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6875      * @return {BasicForm} this
6876      */
6877     setValues : function(values){
6878         if(values instanceof Array){ // array of objects
6879             for(var i = 0, len = values.length; i < len; i++){
6880                 var v = values[i];
6881                 var f = this.findField(v.id);
6882                 if(f){
6883                     f.setValue(v.value);
6884                     if(this.trackResetOnLoad){
6885                         f.originalValue = f.getValue();
6886                     }
6887                 }
6888             }
6889         }else{ // object hash
6890             var field, id;
6891             for(id in values){
6892                 if(typeof values[id] != 'function' && (field = this.findField(id))){
6893                     
6894                     if (field.setFromData && 
6895                         field.valueField && 
6896                         field.displayField &&
6897                         // combos' with local stores can 
6898                         // be queried via setValue()
6899                         // to set their value..
6900                         (field.store && !field.store.isLocal)
6901                         ) {
6902                         // it's a combo
6903                         var sd = { };
6904                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6905                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6906                         field.setFromData(sd);
6907                         
6908                     } else {
6909                         field.setValue(values[id]);
6910                     }
6911                     
6912                     
6913                     if(this.trackResetOnLoad){
6914                         field.originalValue = field.getValue();
6915                     }
6916                 }
6917             }
6918         }
6919          
6920         //Roo.each(this.childForms || [], function (f) {
6921         //    f.setValues(values);
6922         //});
6923                 
6924         return this;
6925     },
6926
6927     /**
6928      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6929      * they are returned as an array.
6930      * @param {Boolean} asString
6931      * @return {Object}
6932      */
6933     getValues : function(asString){
6934         //if (this.childForms) {
6935             // copy values from the child forms
6936         //    Roo.each(this.childForms, function (f) {
6937         //        this.setValues(f.getValues());
6938         //    }, this);
6939         //}
6940         
6941         
6942         
6943         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6944         if(asString === true){
6945             return fs;
6946         }
6947         return Roo.urlDecode(fs);
6948     },
6949     
6950     /**
6951      * Returns the fields in this form as an object with key/value pairs. 
6952      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6953      * @return {Object}
6954      */
6955     getFieldValues : function(with_hidden)
6956     {
6957         var items = this.getItems();
6958         var ret = {};
6959         items.each(function(f){
6960             if (!f.getName()) {
6961                 return;
6962             }
6963             var v = f.getValue();
6964             if (f.inputType =='radio') {
6965                 if (typeof(ret[f.getName()]) == 'undefined') {
6966                     ret[f.getName()] = ''; // empty..
6967                 }
6968                 
6969                 if (!f.el.dom.checked) {
6970                     return;
6971                     
6972                 }
6973                 v = f.el.dom.value;
6974                 
6975             }
6976             
6977             // not sure if this supported any more..
6978             if ((typeof(v) == 'object') && f.getRawValue) {
6979                 v = f.getRawValue() ; // dates..
6980             }
6981             // combo boxes where name != hiddenName...
6982             if (f.name != f.getName()) {
6983                 ret[f.name] = f.getRawValue();
6984             }
6985             ret[f.getName()] = v;
6986         });
6987         
6988         return ret;
6989     },
6990
6991     /**
6992      * Clears all invalid messages in this form.
6993      * @return {BasicForm} this
6994      */
6995     clearInvalid : function(){
6996         var items = this.getItems();
6997         
6998         items.each(function(f){
6999            f.clearInvalid();
7000         });
7001         
7002         
7003         
7004         return this;
7005     },
7006
7007     /**
7008      * Resets this form.
7009      * @return {BasicForm} this
7010      */
7011     reset : function(){
7012         var items = this.getItems();
7013         items.each(function(f){
7014             f.reset();
7015         });
7016         
7017         Roo.each(this.childForms || [], function (f) {
7018             f.reset();
7019         });
7020        
7021         
7022         return this;
7023     },
7024     getItems : function()
7025     {
7026         var r=new Roo.util.MixedCollection(false, function(o){
7027             return o.id || (o.id = Roo.id());
7028         });
7029         var iter = function(el) {
7030             if (el.inputEl) {
7031                 r.add(el);
7032             }
7033             if (!el.items) {
7034                 return;
7035             }
7036             Roo.each(el.items,function(e) {
7037                 iter(e);
7038             });
7039             
7040             
7041         };
7042         
7043         iter(this);
7044         return r;
7045         
7046         
7047         
7048         
7049     }
7050     
7051 });
7052
7053  
7054 /*
7055  * Based on:
7056  * Ext JS Library 1.1.1
7057  * Copyright(c) 2006-2007, Ext JS, LLC.
7058  *
7059  * Originally Released Under LGPL - original licence link has changed is not relivant.
7060  *
7061  * Fork - LGPL
7062  * <script type="text/javascript">
7063  */
7064 /**
7065  * @class Roo.form.VTypes
7066  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7067  * @singleton
7068  */
7069 Roo.form.VTypes = function(){
7070     // closure these in so they are only created once.
7071     var alpha = /^[a-zA-Z_]+$/;
7072     var alphanum = /^[a-zA-Z0-9_]+$/;
7073     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7074     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7075
7076     // All these messages and functions are configurable
7077     return {
7078         /**
7079          * The function used to validate email addresses
7080          * @param {String} value The email address
7081          */
7082         'email' : function(v){
7083             return email.test(v);
7084         },
7085         /**
7086          * The error text to display when the email validation function returns false
7087          * @type String
7088          */
7089         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7090         /**
7091          * The keystroke filter mask to be applied on email input
7092          * @type RegExp
7093          */
7094         'emailMask' : /[a-z0-9_\.\-@]/i,
7095
7096         /**
7097          * The function used to validate URLs
7098          * @param {String} value The URL
7099          */
7100         'url' : function(v){
7101             return url.test(v);
7102         },
7103         /**
7104          * The error text to display when the url validation function returns false
7105          * @type String
7106          */
7107         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7108         
7109         /**
7110          * The function used to validate alpha values
7111          * @param {String} value The value
7112          */
7113         'alpha' : function(v){
7114             return alpha.test(v);
7115         },
7116         /**
7117          * The error text to display when the alpha validation function returns false
7118          * @type String
7119          */
7120         'alphaText' : 'This field should only contain letters and _',
7121         /**
7122          * The keystroke filter mask to be applied on alpha input
7123          * @type RegExp
7124          */
7125         'alphaMask' : /[a-z_]/i,
7126
7127         /**
7128          * The function used to validate alphanumeric values
7129          * @param {String} value The value
7130          */
7131         'alphanum' : function(v){
7132             return alphanum.test(v);
7133         },
7134         /**
7135          * The error text to display when the alphanumeric validation function returns false
7136          * @type String
7137          */
7138         'alphanumText' : 'This field should only contain letters, numbers and _',
7139         /**
7140          * The keystroke filter mask to be applied on alphanumeric input
7141          * @type RegExp
7142          */
7143         'alphanumMask' : /[a-z0-9_]/i
7144     };
7145 }();/*
7146  * - LGPL
7147  *
7148  * Input
7149  * 
7150  */
7151
7152 /**
7153  * @class Roo.bootstrap.Input
7154  * @extends Roo.bootstrap.Component
7155  * Bootstrap Input class
7156  * @cfg {Boolean} disabled is it disabled
7157  * @cfg {String} fieldLabel - the label associated
7158  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7159  * @cfg {String} name name of the input
7160  * @cfg {string} fieldLabel - the label associated
7161  * @cfg {string}  inputType - input / file submit ...
7162  * @cfg {string} placeholder - placeholder to put in text.
7163  * @cfg {string}  before - input group add on before
7164  * @cfg {string} after - input group add on after
7165  * @cfg {string} size - (lg|sm) or leave empty..
7166  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7167  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7168  * @cfg {Number} md colspan out of 12 for computer-sized screens
7169  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7170  * @cfg {string} value default value of the input
7171  * @cfg {Number} labelWidth set the width of label (0-12)
7172  * @cfg {String} labelAlign (top|left)
7173  * @cfg {Boolean} readOnly Specifies that the field should be read-only
7174  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7175
7176  * @cfg {String} align (left|center|right) Default left
7177  * 
7178  * 
7179  * 
7180  * @constructor
7181  * Create a new Input
7182  * @param {Object} config The config object
7183  */
7184
7185 Roo.bootstrap.Input = function(config){
7186     Roo.bootstrap.Input.superclass.constructor.call(this, config);
7187    
7188         this.addEvents({
7189             /**
7190              * @event focus
7191              * Fires when this field receives input focus.
7192              * @param {Roo.form.Field} this
7193              */
7194             focus : true,
7195             /**
7196              * @event blur
7197              * Fires when this field loses input focus.
7198              * @param {Roo.form.Field} this
7199              */
7200             blur : true,
7201             /**
7202              * @event specialkey
7203              * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
7204              * {@link Roo.EventObject#getKey} to determine which key was pressed.
7205              * @param {Roo.form.Field} this
7206              * @param {Roo.EventObject} e The event object
7207              */
7208             specialkey : true,
7209             /**
7210              * @event change
7211              * Fires just before the field blurs if the field value has changed.
7212              * @param {Roo.form.Field} this
7213              * @param {Mixed} newValue The new value
7214              * @param {Mixed} oldValue The original value
7215              */
7216             change : true,
7217             /**
7218              * @event invalid
7219              * Fires after the field has been marked as invalid.
7220              * @param {Roo.form.Field} this
7221              * @param {String} msg The validation message
7222              */
7223             invalid : true,
7224             /**
7225              * @event valid
7226              * Fires after the field has been validated with no errors.
7227              * @param {Roo.form.Field} this
7228              */
7229             valid : true,
7230              /**
7231              * @event keyup
7232              * Fires after the key up
7233              * @param {Roo.form.Field} this
7234              * @param {Roo.EventObject}  e The event Object
7235              */
7236             keyup : true
7237         });
7238 };
7239
7240 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
7241      /**
7242      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7243       automatic validation (defaults to "keyup").
7244      */
7245     validationEvent : "keyup",
7246      /**
7247      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7248      */
7249     validateOnBlur : true,
7250     /**
7251      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7252      */
7253     validationDelay : 250,
7254      /**
7255      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7256      */
7257     focusClass : "x-form-focus",  // not needed???
7258     
7259        
7260     /**
7261      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7262      */
7263     invalidClass : "has-warning",
7264     
7265     /**
7266      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7267      */
7268     validClass : "has-success",
7269     
7270     /**
7271      * @cfg {Boolean} hasFeedback (true|false) default true
7272      */
7273     hasFeedback : true,
7274     
7275     /**
7276      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7277      */
7278     invalidFeedbackClass : "glyphicon-warning-sign",
7279     
7280     /**
7281      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7282      */
7283     validFeedbackClass : "glyphicon-ok",
7284     
7285     /**
7286      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7287      */
7288     selectOnFocus : false,
7289     
7290      /**
7291      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7292      */
7293     maskRe : null,
7294        /**
7295      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7296      */
7297     vtype : null,
7298     
7299       /**
7300      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7301      */
7302     disableKeyFilter : false,
7303     
7304        /**
7305      * @cfg {Boolean} disabled True to disable the field (defaults to false).
7306      */
7307     disabled : false,
7308      /**
7309      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7310      */
7311     allowBlank : true,
7312     /**
7313      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7314      */
7315     blankText : "This field is required",
7316     
7317      /**
7318      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7319      */
7320     minLength : 0,
7321     /**
7322      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7323      */
7324     maxLength : Number.MAX_VALUE,
7325     /**
7326      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7327      */
7328     minLengthText : "The minimum length for this field is {0}",
7329     /**
7330      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7331      */
7332     maxLengthText : "The maximum length for this field is {0}",
7333   
7334     
7335     /**
7336      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7337      * If available, this function will be called only after the basic validators all return true, and will be passed the
7338      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7339      */
7340     validator : null,
7341     /**
7342      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7343      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7344      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
7345      */
7346     regex : null,
7347     /**
7348      * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7349      */
7350     regexText : "",
7351     
7352     autocomplete: false,
7353     
7354     
7355     fieldLabel : '',
7356     inputType : 'text',
7357     
7358     name : false,
7359     placeholder: false,
7360     before : false,
7361     after : false,
7362     size : false,
7363     hasFocus : false,
7364     preventMark: false,
7365     isFormField : true,
7366     value : '',
7367     labelWidth : 2,
7368     labelAlign : false,
7369     readOnly : false,
7370     align : false,
7371     formatedValue : false,
7372     
7373     parentLabelAlign : function()
7374     {
7375         var parent = this;
7376         while (parent.parent()) {
7377             parent = parent.parent();
7378             if (typeof(parent.labelAlign) !='undefined') {
7379                 return parent.labelAlign;
7380             }
7381         }
7382         return 'left';
7383         
7384     },
7385     
7386     getAutoCreate : function(){
7387         
7388         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7389         
7390         var id = Roo.id();
7391         
7392         var cfg = {};
7393         
7394         if(this.inputType != 'hidden'){
7395             cfg.cls = 'form-group' //input-group
7396         }
7397         
7398         var input =  {
7399             tag: 'input',
7400             id : id,
7401             type : this.inputType,
7402             value : this.value,
7403             cls : 'form-control',
7404             placeholder : this.placeholder || '',
7405             autocomplete : this.autocomplete || 'new-password'
7406         };
7407         
7408         
7409         if(this.align){
7410             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7411         }
7412         
7413         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7414             input.maxLength = this.maxLength;
7415         }
7416         
7417         if (this.disabled) {
7418             input.disabled=true;
7419         }
7420         
7421         if (this.readOnly) {
7422             input.readonly=true;
7423         }
7424         
7425         if (this.name) {
7426             input.name = this.name;
7427         }
7428         if (this.size) {
7429             input.cls += ' input-' + this.size;
7430         }
7431         var settings=this;
7432         ['xs','sm','md','lg'].map(function(size){
7433             if (settings[size]) {
7434                 cfg.cls += ' col-' + size + '-' + settings[size];
7435             }
7436         });
7437         
7438         var inputblock = input;
7439         
7440         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7441             
7442             var feedback = {
7443                 tag: 'span',
7444                 cls: 'glyphicon form-control-feedback'
7445             };
7446
7447             inputblock = {
7448                 cls : 'has-feedback',
7449                 cn :  [
7450                     input,
7451                     feedback
7452                 ] 
7453             };  
7454         }
7455          
7456 //        var inputblock = input;
7457         
7458         if (this.before || this.after) {
7459             
7460             inputblock = {
7461                 cls : 'input-group',
7462                 cn :  [] 
7463             };
7464             
7465             if (this.before && typeof(this.before) == 'string') {
7466                 
7467                 inputblock.cn.push({
7468                     tag :'span',
7469                     cls : 'roo-input-before input-group-addon',
7470                     html : this.before
7471                 });
7472             }
7473             if (this.before && typeof(this.before) == 'object') {
7474                 this.before = Roo.factory(this.before);
7475                 Roo.log(this.before);
7476                 inputblock.cn.push({
7477                     tag :'span',
7478                     cls : 'roo-input-before input-group-' +
7479                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7480                 });
7481             }
7482             
7483             inputblock.cn.push(input);
7484             
7485             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7486                 inputblock.cls += ' has-feedback';
7487                 inputblock.cn.push(feedback);
7488             }
7489             
7490             if (this.after && typeof(this.after) == 'string') {
7491                 inputblock.cn.push({
7492                     tag :'span',
7493                     cls : 'roo-input-after input-group-addon',
7494                     html : this.after
7495                 });
7496             }
7497             if (this.after && typeof(this.after) == 'object') {
7498                 this.after = Roo.factory(this.after);
7499                 Roo.log(this.after);
7500                 inputblock.cn.push({
7501                     tag :'span',
7502                     cls : 'roo-input-after input-group-' +
7503                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
7504                 });
7505             }
7506         };
7507         
7508         if (align ==='left' && this.fieldLabel.length) {
7509                 Roo.log("left and has label");
7510                 cfg.cn = [
7511                     
7512                     {
7513                         tag: 'label',
7514                         'for' :  id,
7515                         cls : 'control-label col-sm-' + this.labelWidth,
7516                         html : this.fieldLabel
7517                         
7518                     },
7519                     {
7520                         cls : "col-sm-" + (12 - this.labelWidth), 
7521                         cn: [
7522                             inputblock
7523                         ]
7524                     }
7525                     
7526                 ];
7527         } else if ( this.fieldLabel.length) {
7528                 Roo.log(" label");
7529                  cfg.cn = [
7530                    
7531                     {
7532                         tag: 'label',
7533                         //cls : 'input-group-addon',
7534                         html : this.fieldLabel
7535                         
7536                     },
7537                     
7538                     inputblock
7539                     
7540                 ];
7541
7542         } else {
7543             
7544                 Roo.log(" no label && no align");
7545                 cfg.cn = [
7546                     
7547                         inputblock
7548                     
7549                 ];
7550                 
7551                 
7552         };
7553         Roo.log('input-parentType: ' + this.parentType);
7554         
7555         if (this.parentType === 'Navbar' &&  this.parent().bar) {
7556            cfg.cls += ' navbar-form';
7557            Roo.log(cfg);
7558         }
7559         
7560         return cfg;
7561         
7562     },
7563     /**
7564      * return the real input element.
7565      */
7566     inputEl: function ()
7567     {
7568         return this.el.select('input.form-control',true).first();
7569     },
7570     
7571     tooltipEl : function()
7572     {
7573         return this.inputEl();
7574     },
7575     
7576     setDisabled : function(v)
7577     {
7578         var i  = this.inputEl().dom;
7579         if (!v) {
7580             i.removeAttribute('disabled');
7581             return;
7582             
7583         }
7584         i.setAttribute('disabled','true');
7585     },
7586     initEvents : function()
7587     {
7588           
7589         this.inputEl().on("keydown" , this.fireKey,  this);
7590         this.inputEl().on("focus", this.onFocus,  this);
7591         this.inputEl().on("blur", this.onBlur,  this);
7592         
7593         this.inputEl().relayEvent('keyup', this);
7594
7595         // reference to original value for reset
7596         this.originalValue = this.getValue();
7597         //Roo.form.TextField.superclass.initEvents.call(this);
7598         if(this.validationEvent == 'keyup'){
7599             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7600             this.inputEl().on('keyup', this.filterValidation, this);
7601         }
7602         else if(this.validationEvent !== false){
7603             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7604         }
7605         
7606         if(this.selectOnFocus){
7607             this.on("focus", this.preFocus, this);
7608             
7609         }
7610         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7611             this.inputEl().on("keypress", this.filterKeys, this);
7612         }
7613        /* if(this.grow){
7614             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
7615             this.el.on("click", this.autoSize,  this);
7616         }
7617         */
7618         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7619             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7620         }
7621         
7622         if (typeof(this.before) == 'object') {
7623             this.before.render(this.el.select('.roo-input-before',true).first());
7624         }
7625         if (typeof(this.after) == 'object') {
7626             this.after.render(this.el.select('.roo-input-after',true).first());
7627         }
7628         
7629         
7630     },
7631     filterValidation : function(e){
7632         if(!e.isNavKeyPress()){
7633             this.validationTask.delay(this.validationDelay);
7634         }
7635     },
7636      /**
7637      * Validates the field value
7638      * @return {Boolean} True if the value is valid, else false
7639      */
7640     validate : function(){
7641         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7642         if(this.disabled || this.validateValue(this.getRawValue())){
7643             this.markValid();
7644             return true;
7645         }
7646         
7647         this.markInvalid();
7648         return false;
7649     },
7650     
7651     
7652     /**
7653      * Validates a value according to the field's validation rules and marks the field as invalid
7654      * if the validation fails
7655      * @param {Mixed} value The value to validate
7656      * @return {Boolean} True if the value is valid, else false
7657      */
7658     validateValue : function(value){
7659         if(value.length < 1)  { // if it's blank
7660             if(this.allowBlank){
7661                 return true;
7662             }
7663             return false;
7664         }
7665         
7666         if(value.length < this.minLength){
7667             return false;
7668         }
7669         if(value.length > this.maxLength){
7670             return false;
7671         }
7672         if(this.vtype){
7673             var vt = Roo.form.VTypes;
7674             if(!vt[this.vtype](value, this)){
7675                 return false;
7676             }
7677         }
7678         if(typeof this.validator == "function"){
7679             var msg = this.validator(value);
7680             if(msg !== true){
7681                 return false;
7682             }
7683         }
7684         
7685         if(this.regex && !this.regex.test(value)){
7686             return false;
7687         }
7688         
7689         return true;
7690     },
7691
7692     
7693     
7694      // private
7695     fireKey : function(e){
7696         //Roo.log('field ' + e.getKey());
7697         if(e.isNavKeyPress()){
7698             this.fireEvent("specialkey", this, e);
7699         }
7700     },
7701     focus : function (selectText){
7702         if(this.rendered){
7703             this.inputEl().focus();
7704             if(selectText === true){
7705                 this.inputEl().dom.select();
7706             }
7707         }
7708         return this;
7709     } ,
7710     
7711     onFocus : function(){
7712         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7713            // this.el.addClass(this.focusClass);
7714         }
7715         if(!this.hasFocus){
7716             this.hasFocus = true;
7717             this.startValue = this.getValue();
7718             this.fireEvent("focus", this);
7719         }
7720     },
7721     
7722     beforeBlur : Roo.emptyFn,
7723
7724     
7725     // private
7726     onBlur : function(){
7727         this.beforeBlur();
7728         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7729             //this.el.removeClass(this.focusClass);
7730         }
7731         this.hasFocus = false;
7732         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7733             this.validate();
7734         }
7735         var v = this.getValue();
7736         if(String(v) !== String(this.startValue)){
7737             this.fireEvent('change', this, v, this.startValue);
7738         }
7739         this.fireEvent("blur", this);
7740     },
7741     
7742     /**
7743      * Resets the current field value to the originally loaded value and clears any validation messages
7744      */
7745     reset : function(){
7746         this.setValue(this.originalValue);
7747         this.validate();
7748     },
7749      /**
7750      * Returns the name of the field
7751      * @return {Mixed} name The name field
7752      */
7753     getName: function(){
7754         return this.name;
7755     },
7756      /**
7757      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
7758      * @return {Mixed} value The field value
7759      */
7760     getValue : function(){
7761         
7762         var v = this.inputEl().getValue();
7763         
7764         return v;
7765     },
7766     /**
7767      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
7768      * @return {Mixed} value The field value
7769      */
7770     getRawValue : function(){
7771         var v = this.inputEl().getValue();
7772         
7773         return v;
7774     },
7775     
7776     /**
7777      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
7778      * @param {Mixed} value The value to set
7779      */
7780     setRawValue : function(v){
7781         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7782     },
7783     
7784     selectText : function(start, end){
7785         var v = this.getRawValue();
7786         if(v.length > 0){
7787             start = start === undefined ? 0 : start;
7788             end = end === undefined ? v.length : end;
7789             var d = this.inputEl().dom;
7790             if(d.setSelectionRange){
7791                 d.setSelectionRange(start, end);
7792             }else if(d.createTextRange){
7793                 var range = d.createTextRange();
7794                 range.moveStart("character", start);
7795                 range.moveEnd("character", v.length-end);
7796                 range.select();
7797             }
7798         }
7799     },
7800     
7801     /**
7802      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
7803      * @param {Mixed} value The value to set
7804      */
7805     setValue : function(v){
7806         this.value = v;
7807         if(this.rendered){
7808             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7809             this.validate();
7810         }
7811     },
7812     
7813     /*
7814     processValue : function(value){
7815         if(this.stripCharsRe){
7816             var newValue = value.replace(this.stripCharsRe, '');
7817             if(newValue !== value){
7818                 this.setRawValue(newValue);
7819                 return newValue;
7820             }
7821         }
7822         return value;
7823     },
7824   */
7825     preFocus : function(){
7826         
7827         if(this.selectOnFocus){
7828             this.inputEl().dom.select();
7829         }
7830     },
7831     filterKeys : function(e){
7832         var k = e.getKey();
7833         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
7834             return;
7835         }
7836         var c = e.getCharCode(), cc = String.fromCharCode(c);
7837         if(Roo.isIE && (e.isSpecialKey() || !cc)){
7838             return;
7839         }
7840         if(!this.maskRe.test(cc)){
7841             e.stopEvent();
7842         }
7843     },
7844      /**
7845      * Clear any invalid styles/messages for this field
7846      */
7847     clearInvalid : function(){
7848         
7849         if(!this.el || this.preventMark){ // not rendered
7850             return;
7851         }
7852         this.el.removeClass(this.invalidClass);
7853         
7854         this.fireEvent('valid', this);
7855     },
7856     
7857      /**
7858      * Mark this field as valid
7859      */
7860     markValid : function(){
7861         if(!this.el  || this.preventMark){ // not rendered
7862             return;
7863         }
7864         
7865         this.el.removeClass([this.invalidClass, this.validClass]);
7866         
7867         if(this.disabled || this.allowBlank){
7868             return;
7869         }
7870         
7871         this.el.addClass(this.validClass);
7872         
7873         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
7874             
7875             var feedback = this.el.select('.form-control-feedback', true).first();
7876             
7877             if(feedback){
7878                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7879                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
7880             }
7881             
7882         }
7883         
7884         this.fireEvent('valid', this);
7885     },
7886     
7887      /**
7888      * Mark this field as invalid
7889      * @param {String} msg The validation message
7890      */
7891     markInvalid : function(msg){
7892         if(!this.el  || this.preventMark){ // not rendered
7893             return;
7894         }
7895         
7896         this.el.removeClass([this.invalidClass, this.validClass]);
7897         
7898         if(this.disabled || this.allowBlank){
7899             return;
7900         }
7901         
7902         this.el.addClass(this.invalidClass);
7903         
7904         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7905             
7906             var feedback = this.el.select('.form-control-feedback', true).first();
7907             
7908             if(feedback){
7909                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
7910                 
7911                 if(this.getValue().length){
7912                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
7913                 }
7914                 
7915             }
7916             
7917         }
7918         
7919         this.fireEvent('invalid', this, msg);
7920     },
7921     // private
7922     SafariOnKeyDown : function(event)
7923     {
7924         // this is a workaround for a password hang bug on chrome/ webkit.
7925         
7926         var isSelectAll = false;
7927         
7928         if(this.inputEl().dom.selectionEnd > 0){
7929             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7930         }
7931         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7932             event.preventDefault();
7933             this.setValue('');
7934             return;
7935         }
7936         
7937         if(isSelectAll  && event.getCharCode() > 31){ // not backspace and delete key
7938             
7939             event.preventDefault();
7940             // this is very hacky as keydown always get's upper case.
7941             //
7942             var cc = String.fromCharCode(event.getCharCode());
7943             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
7944             
7945         }
7946     },
7947     adjustWidth : function(tag, w){
7948         tag = tag.toLowerCase();
7949         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7950             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7951                 if(tag == 'input'){
7952                     return w + 2;
7953                 }
7954                 if(tag == 'textarea'){
7955                     return w-2;
7956                 }
7957             }else if(Roo.isOpera){
7958                 if(tag == 'input'){
7959                     return w + 2;
7960                 }
7961                 if(tag == 'textarea'){
7962                     return w-2;
7963                 }
7964             }
7965         }
7966         return w;
7967     }
7968     
7969 });
7970
7971  
7972 /*
7973  * - LGPL
7974  *
7975  * Input
7976  * 
7977  */
7978
7979 /**
7980  * @class Roo.bootstrap.TextArea
7981  * @extends Roo.bootstrap.Input
7982  * Bootstrap TextArea class
7983  * @cfg {Number} cols Specifies the visible width of a text area
7984  * @cfg {Number} rows Specifies the visible number of lines in a text area
7985  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7986  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7987  * @cfg {string} html text
7988  * 
7989  * @constructor
7990  * Create a new TextArea
7991  * @param {Object} config The config object
7992  */
7993
7994 Roo.bootstrap.TextArea = function(config){
7995     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7996    
7997 };
7998
7999 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
8000      
8001     cols : false,
8002     rows : 5,
8003     readOnly : false,
8004     warp : 'soft',
8005     resize : false,
8006     value: false,
8007     html: false,
8008     
8009     getAutoCreate : function(){
8010         
8011         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8012         
8013         var id = Roo.id();
8014         
8015         var cfg = {};
8016         
8017         var input =  {
8018             tag: 'textarea',
8019             id : id,
8020             warp : this.warp,
8021             rows : this.rows,
8022             value : this.value || '',
8023             html: this.html || '',
8024             cls : 'form-control',
8025             placeholder : this.placeholder || '' 
8026             
8027         };
8028         
8029         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8030             input.maxLength = this.maxLength;
8031         }
8032         
8033         if(this.resize){
8034             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8035         }
8036         
8037         if(this.cols){
8038             input.cols = this.cols;
8039         }
8040         
8041         if (this.readOnly) {
8042             input.readonly = true;
8043         }
8044         
8045         if (this.name) {
8046             input.name = this.name;
8047         }
8048         
8049         if (this.size) {
8050             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8051         }
8052         
8053         var settings=this;
8054         ['xs','sm','md','lg'].map(function(size){
8055             if (settings[size]) {
8056                 cfg.cls += ' col-' + size + '-' + settings[size];
8057             }
8058         });
8059         
8060         var inputblock = input;
8061         
8062         if(this.hasFeedback && !this.allowBlank){
8063             
8064             var feedback = {
8065                 tag: 'span',
8066                 cls: 'glyphicon form-control-feedback'
8067             };
8068
8069             inputblock = {
8070                 cls : 'has-feedback',
8071                 cn :  [
8072                     input,
8073                     feedback
8074                 ] 
8075             };  
8076         }
8077         
8078         
8079         if (this.before || this.after) {
8080             
8081             inputblock = {
8082                 cls : 'input-group',
8083                 cn :  [] 
8084             };
8085             if (this.before) {
8086                 inputblock.cn.push({
8087                     tag :'span',
8088                     cls : 'input-group-addon',
8089                     html : this.before
8090                 });
8091             }
8092             
8093             inputblock.cn.push(input);
8094             
8095             if(this.hasFeedback && !this.allowBlank){
8096                 inputblock.cls += ' has-feedback';
8097                 inputblock.cn.push(feedback);
8098             }
8099             
8100             if (this.after) {
8101                 inputblock.cn.push({
8102                     tag :'span',
8103                     cls : 'input-group-addon',
8104                     html : this.after
8105                 });
8106             }
8107             
8108         }
8109         
8110         if (align ==='left' && this.fieldLabel.length) {
8111                 Roo.log("left and has label");
8112                 cfg.cn = [
8113                     
8114                     {
8115                         tag: 'label',
8116                         'for' :  id,
8117                         cls : 'control-label col-sm-' + this.labelWidth,
8118                         html : this.fieldLabel
8119                         
8120                     },
8121                     {
8122                         cls : "col-sm-" + (12 - this.labelWidth), 
8123                         cn: [
8124                             inputblock
8125                         ]
8126                     }
8127                     
8128                 ];
8129         } else if ( this.fieldLabel.length) {
8130                 Roo.log(" label");
8131                  cfg.cn = [
8132                    
8133                     {
8134                         tag: 'label',
8135                         //cls : 'input-group-addon',
8136                         html : this.fieldLabel
8137                         
8138                     },
8139                     
8140                     inputblock
8141                     
8142                 ];
8143
8144         } else {
8145             
8146                    Roo.log(" no label && no align");
8147                 cfg.cn = [
8148                     
8149                         inputblock
8150                     
8151                 ];
8152                 
8153                 
8154         }
8155         
8156         if (this.disabled) {
8157             input.disabled=true;
8158         }
8159         
8160         return cfg;
8161         
8162     },
8163     /**
8164      * return the real textarea element.
8165      */
8166     inputEl: function ()
8167     {
8168         return this.el.select('textarea.form-control',true).first();
8169     }
8170 });
8171
8172  
8173 /*
8174  * - LGPL
8175  *
8176  * trigger field - base class for combo..
8177  * 
8178  */
8179  
8180 /**
8181  * @class Roo.bootstrap.TriggerField
8182  * @extends Roo.bootstrap.Input
8183  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8184  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8185  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8186  * for which you can provide a custom implementation.  For example:
8187  * <pre><code>
8188 var trigger = new Roo.bootstrap.TriggerField();
8189 trigger.onTriggerClick = myTriggerFn;
8190 trigger.applyTo('my-field');
8191 </code></pre>
8192  *
8193  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8194  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8195  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
8196  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8197  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8198
8199  * @constructor
8200  * Create a new TriggerField.
8201  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8202  * to the base TextField)
8203  */
8204 Roo.bootstrap.TriggerField = function(config){
8205     this.mimicing = false;
8206     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8207 };
8208
8209 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
8210     /**
8211      * @cfg {String} triggerClass A CSS class to apply to the trigger
8212      */
8213      /**
8214      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8215      */
8216     hideTrigger:false,
8217
8218     /** @cfg {Boolean} grow @hide */
8219     /** @cfg {Number} growMin @hide */
8220     /** @cfg {Number} growMax @hide */
8221
8222     /**
8223      * @hide 
8224      * @method
8225      */
8226     autoSize: Roo.emptyFn,
8227     // private
8228     monitorTab : true,
8229     // private
8230     deferHeight : true,
8231
8232     
8233     actionMode : 'wrap',
8234     
8235     caret : false,
8236     
8237     
8238     getAutoCreate : function(){
8239        
8240         var align = this.labelAlign || this.parentLabelAlign();
8241         
8242         var id = Roo.id();
8243         
8244         var cfg = {
8245             cls: 'form-group' //input-group
8246         };
8247         
8248         
8249         var input =  {
8250             tag: 'input',
8251             id : id,
8252             type : this.inputType,
8253             cls : 'form-control',
8254             autocomplete: 'new-password',
8255             placeholder : this.placeholder || '' 
8256             
8257         };
8258         if (this.name) {
8259             input.name = this.name;
8260         }
8261         if (this.size) {
8262             input.cls += ' input-' + this.size;
8263         }
8264         
8265         if (this.disabled) {
8266             input.disabled=true;
8267         }
8268         
8269         var inputblock = input;
8270         
8271         if(this.hasFeedback && !this.allowBlank){
8272             
8273             var feedback = {
8274                 tag: 'span',
8275                 cls: 'glyphicon form-control-feedback'
8276             };
8277
8278             inputblock = {
8279                 cls : 'has-feedback',
8280                 cn :  [
8281                     input,
8282                     feedback
8283                 ] 
8284             };  
8285         }
8286         
8287         if (this.before || this.after) {
8288             
8289             inputblock = {
8290                 cls : 'input-group',
8291                 cn :  [] 
8292             };
8293             if (this.before) {
8294                 inputblock.cn.push({
8295                     tag :'span',
8296                     cls : 'input-group-addon',
8297                     html : this.before
8298                 });
8299             }
8300             
8301             inputblock.cn.push(input);
8302             
8303             if(this.hasFeedback && !this.allowBlank){
8304                 inputblock.cls += ' has-feedback';
8305                 inputblock.cn.push(feedback);
8306             }
8307             
8308             if (this.after) {
8309                 inputblock.cn.push({
8310                     tag :'span',
8311                     cls : 'input-group-addon',
8312                     html : this.after
8313                 });
8314             }
8315             
8316         };
8317         
8318         var box = {
8319             tag: 'div',
8320             cn: [
8321                 {
8322                     tag: 'input',
8323                     type : 'hidden',
8324                     cls: 'form-hidden-field'
8325                 },
8326                 inputblock
8327             ]
8328             
8329         };
8330         
8331         if(this.multiple){
8332             Roo.log('multiple');
8333             
8334             box = {
8335                 tag: 'div',
8336                 cn: [
8337                     {
8338                         tag: 'input',
8339                         type : 'hidden',
8340                         cls: 'form-hidden-field'
8341                     },
8342                     {
8343                         tag: 'ul',
8344                         cls: 'select2-choices',
8345                         cn:[
8346                             {
8347                                 tag: 'li',
8348                                 cls: 'select2-search-field',
8349                                 cn: [
8350
8351                                     inputblock
8352                                 ]
8353                             }
8354                         ]
8355                     }
8356                 ]
8357             }
8358         };
8359         
8360         var combobox = {
8361             cls: 'select2-container input-group',
8362             cn: [
8363                 box
8364 //                {
8365 //                    tag: 'ul',
8366 //                    cls: 'typeahead typeahead-long dropdown-menu',
8367 //                    style: 'display:none'
8368 //                }
8369             ]
8370         };
8371         
8372         if(!this.multiple && this.showToggleBtn){
8373             
8374             var caret = {
8375                         tag: 'span',
8376                         cls: 'caret'
8377              };
8378             if (this.caret != false) {
8379                 caret = {
8380                      tag: 'i',
8381                      cls: 'fa fa-' + this.caret
8382                 };
8383                 
8384             }
8385             
8386             combobox.cn.push({
8387                 tag :'span',
8388                 cls : 'input-group-addon btn dropdown-toggle',
8389                 cn : [
8390                     caret,
8391                     {
8392                         tag: 'span',
8393                         cls: 'combobox-clear',
8394                         cn  : [
8395                             {
8396                                 tag : 'i',
8397                                 cls: 'icon-remove'
8398                             }
8399                         ]
8400                     }
8401                 ]
8402
8403             })
8404         }
8405         
8406         if(this.multiple){
8407             combobox.cls += ' select2-container-multi';
8408         }
8409         
8410         if (align ==='left' && this.fieldLabel.length) {
8411             
8412                 Roo.log("left and has label");
8413                 cfg.cn = [
8414                     
8415                     {
8416                         tag: 'label',
8417                         'for' :  id,
8418                         cls : 'control-label col-sm-' + this.labelWidth,
8419                         html : this.fieldLabel
8420                         
8421                     },
8422                     {
8423                         cls : "col-sm-" + (12 - this.labelWidth), 
8424                         cn: [
8425                             combobox
8426                         ]
8427                     }
8428                     
8429                 ];
8430         } else if ( this.fieldLabel.length) {
8431                 Roo.log(" label");
8432                  cfg.cn = [
8433                    
8434                     {
8435                         tag: 'label',
8436                         //cls : 'input-group-addon',
8437                         html : this.fieldLabel
8438                         
8439                     },
8440                     
8441                     combobox
8442                     
8443                 ];
8444
8445         } else {
8446             
8447                 Roo.log(" no label && no align");
8448                 cfg = combobox
8449                      
8450                 
8451         }
8452          
8453         var settings=this;
8454         ['xs','sm','md','lg'].map(function(size){
8455             if (settings[size]) {
8456                 cfg.cls += ' col-' + size + '-' + settings[size];
8457             }
8458         });
8459         
8460         return cfg;
8461         
8462     },
8463     
8464     
8465     
8466     // private
8467     onResize : function(w, h){
8468 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8469 //        if(typeof w == 'number'){
8470 //            var x = w - this.trigger.getWidth();
8471 //            this.inputEl().setWidth(this.adjustWidth('input', x));
8472 //            this.trigger.setStyle('left', x+'px');
8473 //        }
8474     },
8475
8476     // private
8477     adjustSize : Roo.BoxComponent.prototype.adjustSize,
8478
8479     // private
8480     getResizeEl : function(){
8481         return this.inputEl();
8482     },
8483
8484     // private
8485     getPositionEl : function(){
8486         return this.inputEl();
8487     },
8488
8489     // private
8490     alignErrorIcon : function(){
8491         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8492     },
8493
8494     // private
8495     initEvents : function(){
8496         
8497         this.createList();
8498         
8499         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8500         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8501         if(!this.multiple && this.showToggleBtn){
8502             this.trigger = this.el.select('span.dropdown-toggle',true).first();
8503             if(this.hideTrigger){
8504                 this.trigger.setDisplayed(false);
8505             }
8506             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8507         }
8508         
8509         if(this.multiple){
8510             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8511         }
8512         
8513         //this.trigger.addClassOnOver('x-form-trigger-over');
8514         //this.trigger.addClassOnClick('x-form-trigger-click');
8515         
8516         //if(!this.width){
8517         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8518         //}
8519     },
8520     
8521     createList : function()
8522     {
8523         this.list = Roo.get(document.body).createChild({
8524             tag: 'ul',
8525             cls: 'typeahead typeahead-long dropdown-menu',
8526             style: 'display:none'
8527         });
8528         
8529         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8530         
8531     },
8532
8533     // private
8534     initTrigger : function(){
8535        
8536     },
8537
8538     // private
8539     onDestroy : function(){
8540         if(this.trigger){
8541             this.trigger.removeAllListeners();
8542           //  this.trigger.remove();
8543         }
8544         //if(this.wrap){
8545         //    this.wrap.remove();
8546         //}
8547         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8548     },
8549
8550     // private
8551     onFocus : function(){
8552         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8553         /*
8554         if(!this.mimicing){
8555             this.wrap.addClass('x-trigger-wrap-focus');
8556             this.mimicing = true;
8557             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8558             if(this.monitorTab){
8559                 this.el.on("keydown", this.checkTab, this);
8560             }
8561         }
8562         */
8563     },
8564
8565     // private
8566     checkTab : function(e){
8567         if(e.getKey() == e.TAB){
8568             this.triggerBlur();
8569         }
8570     },
8571
8572     // private
8573     onBlur : function(){
8574         // do nothing
8575     },
8576
8577     // private
8578     mimicBlur : function(e, t){
8579         /*
8580         if(!this.wrap.contains(t) && this.validateBlur()){
8581             this.triggerBlur();
8582         }
8583         */
8584     },
8585
8586     // private
8587     triggerBlur : function(){
8588         this.mimicing = false;
8589         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8590         if(this.monitorTab){
8591             this.el.un("keydown", this.checkTab, this);
8592         }
8593         //this.wrap.removeClass('x-trigger-wrap-focus');
8594         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8595     },
8596
8597     // private
8598     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8599     validateBlur : function(e, t){
8600         return true;
8601     },
8602
8603     // private
8604     onDisable : function(){
8605         this.inputEl().dom.disabled = true;
8606         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8607         //if(this.wrap){
8608         //    this.wrap.addClass('x-item-disabled');
8609         //}
8610     },
8611
8612     // private
8613     onEnable : function(){
8614         this.inputEl().dom.disabled = false;
8615         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8616         //if(this.wrap){
8617         //    this.el.removeClass('x-item-disabled');
8618         //}
8619     },
8620
8621     // private
8622     onShow : function(){
8623         var ae = this.getActionEl();
8624         
8625         if(ae){
8626             ae.dom.style.display = '';
8627             ae.dom.style.visibility = 'visible';
8628         }
8629     },
8630
8631     // private
8632     
8633     onHide : function(){
8634         var ae = this.getActionEl();
8635         ae.dom.style.display = 'none';
8636     },
8637
8638     /**
8639      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
8640      * by an implementing function.
8641      * @method
8642      * @param {EventObject} e
8643      */
8644     onTriggerClick : Roo.emptyFn
8645 });
8646  /*
8647  * Based on:
8648  * Ext JS Library 1.1.1
8649  * Copyright(c) 2006-2007, Ext JS, LLC.
8650  *
8651  * Originally Released Under LGPL - original licence link has changed is not relivant.
8652  *
8653  * Fork - LGPL
8654  * <script type="text/javascript">
8655  */
8656
8657
8658 /**
8659  * @class Roo.data.SortTypes
8660  * @singleton
8661  * Defines the default sorting (casting?) comparison functions used when sorting data.
8662  */
8663 Roo.data.SortTypes = {
8664     /**
8665      * Default sort that does nothing
8666      * @param {Mixed} s The value being converted
8667      * @return {Mixed} The comparison value
8668      */
8669     none : function(s){
8670         return s;
8671     },
8672     
8673     /**
8674      * The regular expression used to strip tags
8675      * @type {RegExp}
8676      * @property
8677      */
8678     stripTagsRE : /<\/?[^>]+>/gi,
8679     
8680     /**
8681      * Strips all HTML tags to sort on text only
8682      * @param {Mixed} s The value being converted
8683      * @return {String} The comparison value
8684      */
8685     asText : function(s){
8686         return String(s).replace(this.stripTagsRE, "");
8687     },
8688     
8689     /**
8690      * Strips all HTML tags to sort on text only - Case insensitive
8691      * @param {Mixed} s The value being converted
8692      * @return {String} The comparison value
8693      */
8694     asUCText : function(s){
8695         return String(s).toUpperCase().replace(this.stripTagsRE, "");
8696     },
8697     
8698     /**
8699      * Case insensitive string
8700      * @param {Mixed} s The value being converted
8701      * @return {String} The comparison value
8702      */
8703     asUCString : function(s) {
8704         return String(s).toUpperCase();
8705     },
8706     
8707     /**
8708      * Date sorting
8709      * @param {Mixed} s The value being converted
8710      * @return {Number} The comparison value
8711      */
8712     asDate : function(s) {
8713         if(!s){
8714             return 0;
8715         }
8716         if(s instanceof Date){
8717             return s.getTime();
8718         }
8719         return Date.parse(String(s));
8720     },
8721     
8722     /**
8723      * Float sorting
8724      * @param {Mixed} s The value being converted
8725      * @return {Float} The comparison value
8726      */
8727     asFloat : function(s) {
8728         var val = parseFloat(String(s).replace(/,/g, ""));
8729         if(isNaN(val)) val = 0;
8730         return val;
8731     },
8732     
8733     /**
8734      * Integer sorting
8735      * @param {Mixed} s The value being converted
8736      * @return {Number} The comparison value
8737      */
8738     asInt : function(s) {
8739         var val = parseInt(String(s).replace(/,/g, ""));
8740         if(isNaN(val)) val = 0;
8741         return val;
8742     }
8743 };/*
8744  * Based on:
8745  * Ext JS Library 1.1.1
8746  * Copyright(c) 2006-2007, Ext JS, LLC.
8747  *
8748  * Originally Released Under LGPL - original licence link has changed is not relivant.
8749  *
8750  * Fork - LGPL
8751  * <script type="text/javascript">
8752  */
8753
8754 /**
8755 * @class Roo.data.Record
8756  * Instances of this class encapsulate both record <em>definition</em> information, and record
8757  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8758  * to access Records cached in an {@link Roo.data.Store} object.<br>
8759  * <p>
8760  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8761  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8762  * objects.<br>
8763  * <p>
8764  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8765  * @constructor
8766  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8767  * {@link #create}. The parameters are the same.
8768  * @param {Array} data An associative Array of data values keyed by the field name.
8769  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8770  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8771  * not specified an integer id is generated.
8772  */
8773 Roo.data.Record = function(data, id){
8774     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8775     this.data = data;
8776 };
8777
8778 /**
8779  * Generate a constructor for a specific record layout.
8780  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8781  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8782  * Each field definition object may contain the following properties: <ul>
8783  * <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,
8784  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8785  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8786  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8787  * is being used, then this is a string containing the javascript expression to reference the data relative to 
8788  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8789  * to the data item relative to the record element. If the mapping expression is the same as the field name,
8790  * this may be omitted.</p></li>
8791  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8792  * <ul><li>auto (Default, implies no conversion)</li>
8793  * <li>string</li>
8794  * <li>int</li>
8795  * <li>float</li>
8796  * <li>boolean</li>
8797  * <li>date</li></ul></p></li>
8798  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8799  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8800  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8801  * by the Reader into an object that will be stored in the Record. It is passed the
8802  * following parameters:<ul>
8803  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8804  * </ul></p></li>
8805  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8806  * </ul>
8807  * <br>usage:<br><pre><code>
8808 var TopicRecord = Roo.data.Record.create(
8809     {name: 'title', mapping: 'topic_title'},
8810     {name: 'author', mapping: 'username'},
8811     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8812     {name: 'lastPost', mapping: 'post_time', type: 'date'},
8813     {name: 'lastPoster', mapping: 'user2'},
8814     {name: 'excerpt', mapping: 'post_text'}
8815 );
8816
8817 var myNewRecord = new TopicRecord({
8818     title: 'Do my job please',
8819     author: 'noobie',
8820     totalPosts: 1,
8821     lastPost: new Date(),
8822     lastPoster: 'Animal',
8823     excerpt: 'No way dude!'
8824 });
8825 myStore.add(myNewRecord);
8826 </code></pre>
8827  * @method create
8828  * @static
8829  */
8830 Roo.data.Record.create = function(o){
8831     var f = function(){
8832         f.superclass.constructor.apply(this, arguments);
8833     };
8834     Roo.extend(f, Roo.data.Record);
8835     var p = f.prototype;
8836     p.fields = new Roo.util.MixedCollection(false, function(field){
8837         return field.name;
8838     });
8839     for(var i = 0, len = o.length; i < len; i++){
8840         p.fields.add(new Roo.data.Field(o[i]));
8841     }
8842     f.getField = function(name){
8843         return p.fields.get(name);  
8844     };
8845     return f;
8846 };
8847
8848 Roo.data.Record.AUTO_ID = 1000;
8849 Roo.data.Record.EDIT = 'edit';
8850 Roo.data.Record.REJECT = 'reject';
8851 Roo.data.Record.COMMIT = 'commit';
8852
8853 Roo.data.Record.prototype = {
8854     /**
8855      * Readonly flag - true if this record has been modified.
8856      * @type Boolean
8857      */
8858     dirty : false,
8859     editing : false,
8860     error: null,
8861     modified: null,
8862
8863     // private
8864     join : function(store){
8865         this.store = store;
8866     },
8867
8868     /**
8869      * Set the named field to the specified value.
8870      * @param {String} name The name of the field to set.
8871      * @param {Object} value The value to set the field to.
8872      */
8873     set : function(name, value){
8874         if(this.data[name] == value){
8875             return;
8876         }
8877         this.dirty = true;
8878         if(!this.modified){
8879             this.modified = {};
8880         }
8881         if(typeof this.modified[name] == 'undefined'){
8882             this.modified[name] = this.data[name];
8883         }
8884         this.data[name] = value;
8885         if(!this.editing && this.store){
8886             this.store.afterEdit(this);
8887         }       
8888     },
8889
8890     /**
8891      * Get the value of the named field.
8892      * @param {String} name The name of the field to get the value of.
8893      * @return {Object} The value of the field.
8894      */
8895     get : function(name){
8896         return this.data[name]; 
8897     },
8898
8899     // private
8900     beginEdit : function(){
8901         this.editing = true;
8902         this.modified = {}; 
8903     },
8904
8905     // private
8906     cancelEdit : function(){
8907         this.editing = false;
8908         delete this.modified;
8909     },
8910
8911     // private
8912     endEdit : function(){
8913         this.editing = false;
8914         if(this.dirty && this.store){
8915             this.store.afterEdit(this);
8916         }
8917     },
8918
8919     /**
8920      * Usually called by the {@link Roo.data.Store} which owns the Record.
8921      * Rejects all changes made to the Record since either creation, or the last commit operation.
8922      * Modified fields are reverted to their original values.
8923      * <p>
8924      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8925      * of reject operations.
8926      */
8927     reject : function(){
8928         var m = this.modified;
8929         for(var n in m){
8930             if(typeof m[n] != "function"){
8931                 this.data[n] = m[n];
8932             }
8933         }
8934         this.dirty = false;
8935         delete this.modified;
8936         this.editing = false;
8937         if(this.store){
8938             this.store.afterReject(this);
8939         }
8940     },
8941
8942     /**
8943      * Usually called by the {@link Roo.data.Store} which owns the Record.
8944      * Commits all changes made to the Record since either creation, or the last commit operation.
8945      * <p>
8946      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
8947      * of commit operations.
8948      */
8949     commit : function(){
8950         this.dirty = false;
8951         delete this.modified;
8952         this.editing = false;
8953         if(this.store){
8954             this.store.afterCommit(this);
8955         }
8956     },
8957
8958     // private
8959     hasError : function(){
8960         return this.error != null;
8961     },
8962
8963     // private
8964     clearError : function(){
8965         this.error = null;
8966     },
8967
8968     /**
8969      * Creates a copy of this record.
8970      * @param {String} id (optional) A new record id if you don't want to use this record's id
8971      * @return {Record}
8972      */
8973     copy : function(newId) {
8974         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8975     }
8976 };/*
8977  * Based on:
8978  * Ext JS Library 1.1.1
8979  * Copyright(c) 2006-2007, Ext JS, LLC.
8980  *
8981  * Originally Released Under LGPL - original licence link has changed is not relivant.
8982  *
8983  * Fork - LGPL
8984  * <script type="text/javascript">
8985  */
8986
8987
8988
8989 /**
8990  * @class Roo.data.Store
8991  * @extends Roo.util.Observable
8992  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8993  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8994  * <p>
8995  * 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
8996  * has no knowledge of the format of the data returned by the Proxy.<br>
8997  * <p>
8998  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8999  * instances from the data object. These records are cached and made available through accessor functions.
9000  * @constructor
9001  * Creates a new Store.
9002  * @param {Object} config A config object containing the objects needed for the Store to access data,
9003  * and read the data into Records.
9004  */
9005 Roo.data.Store = function(config){
9006     this.data = new Roo.util.MixedCollection(false);
9007     this.data.getKey = function(o){
9008         return o.id;
9009     };
9010     this.baseParams = {};
9011     // private
9012     this.paramNames = {
9013         "start" : "start",
9014         "limit" : "limit",
9015         "sort" : "sort",
9016         "dir" : "dir",
9017         "multisort" : "_multisort"
9018     };
9019
9020     if(config && config.data){
9021         this.inlineData = config.data;
9022         delete config.data;
9023     }
9024
9025     Roo.apply(this, config);
9026     
9027     if(this.reader){ // reader passed
9028         this.reader = Roo.factory(this.reader, Roo.data);
9029         this.reader.xmodule = this.xmodule || false;
9030         if(!this.recordType){
9031             this.recordType = this.reader.recordType;
9032         }
9033         if(this.reader.onMetaChange){
9034             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9035         }
9036     }
9037
9038     if(this.recordType){
9039         this.fields = this.recordType.prototype.fields;
9040     }
9041     this.modified = [];
9042
9043     this.addEvents({
9044         /**
9045          * @event datachanged
9046          * Fires when the data cache has changed, and a widget which is using this Store
9047          * as a Record cache should refresh its view.
9048          * @param {Store} this
9049          */
9050         datachanged : true,
9051         /**
9052          * @event metachange
9053          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9054          * @param {Store} this
9055          * @param {Object} meta The JSON metadata
9056          */
9057         metachange : true,
9058         /**
9059          * @event add
9060          * Fires when Records have been added to the Store
9061          * @param {Store} this
9062          * @param {Roo.data.Record[]} records The array of Records added
9063          * @param {Number} index The index at which the record(s) were added
9064          */
9065         add : true,
9066         /**
9067          * @event remove
9068          * Fires when a Record has been removed from the Store
9069          * @param {Store} this
9070          * @param {Roo.data.Record} record The Record that was removed
9071          * @param {Number} index The index at which the record was removed
9072          */
9073         remove : true,
9074         /**
9075          * @event update
9076          * Fires when a Record has been updated
9077          * @param {Store} this
9078          * @param {Roo.data.Record} record The Record that was updated
9079          * @param {String} operation The update operation being performed.  Value may be one of:
9080          * <pre><code>
9081  Roo.data.Record.EDIT
9082  Roo.data.Record.REJECT
9083  Roo.data.Record.COMMIT
9084          * </code></pre>
9085          */
9086         update : true,
9087         /**
9088          * @event clear
9089          * Fires when the data cache has been cleared.
9090          * @param {Store} this
9091          */
9092         clear : true,
9093         /**
9094          * @event beforeload
9095          * Fires before a request is made for a new data object.  If the beforeload handler returns false
9096          * the load action will be canceled.
9097          * @param {Store} this
9098          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9099          */
9100         beforeload : true,
9101         /**
9102          * @event beforeloadadd
9103          * Fires after a new set of Records has been loaded.
9104          * @param {Store} this
9105          * @param {Roo.data.Record[]} records The Records that were loaded
9106          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9107          */
9108         beforeloadadd : true,
9109         /**
9110          * @event load
9111          * Fires after a new set of Records has been loaded, before they are added to the store.
9112          * @param {Store} this
9113          * @param {Roo.data.Record[]} records The Records that were loaded
9114          * @param {Object} options The loading options that were specified (see {@link #load} for details)
9115          * @params {Object} return from reader
9116          */
9117         load : true,
9118         /**
9119          * @event loadexception
9120          * Fires if an exception occurs in the Proxy during loading.
9121          * Called with the signature of the Proxy's "loadexception" event.
9122          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9123          * 
9124          * @param {Proxy} 
9125          * @param {Object} return from JsonData.reader() - success, totalRecords, records
9126          * @param {Object} load options 
9127          * @param {Object} jsonData from your request (normally this contains the Exception)
9128          */
9129         loadexception : true
9130     });
9131     
9132     if(this.proxy){
9133         this.proxy = Roo.factory(this.proxy, Roo.data);
9134         this.proxy.xmodule = this.xmodule || false;
9135         this.relayEvents(this.proxy,  ["loadexception"]);
9136     }
9137     this.sortToggle = {};
9138     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9139
9140     Roo.data.Store.superclass.constructor.call(this);
9141
9142     if(this.inlineData){
9143         this.loadData(this.inlineData);
9144         delete this.inlineData;
9145     }
9146 };
9147
9148 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9149      /**
9150     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
9151     * without a remote query - used by combo/forms at present.
9152     */
9153     
9154     /**
9155     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9156     */
9157     /**
9158     * @cfg {Array} data Inline data to be loaded when the store is initialized.
9159     */
9160     /**
9161     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9162     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9163     */
9164     /**
9165     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9166     * on any HTTP request
9167     */
9168     /**
9169     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9170     */
9171     /**
9172     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9173     */
9174     multiSort: false,
9175     /**
9176     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9177     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9178     */
9179     remoteSort : false,
9180
9181     /**
9182     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9183      * loaded or when a record is removed. (defaults to false).
9184     */
9185     pruneModifiedRecords : false,
9186
9187     // private
9188     lastOptions : null,
9189
9190     /**
9191      * Add Records to the Store and fires the add event.
9192      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9193      */
9194     add : function(records){
9195         records = [].concat(records);
9196         for(var i = 0, len = records.length; i < len; i++){
9197             records[i].join(this);
9198         }
9199         var index = this.data.length;
9200         this.data.addAll(records);
9201         this.fireEvent("add", this, records, index);
9202     },
9203
9204     /**
9205      * Remove a Record from the Store and fires the remove event.
9206      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9207      */
9208     remove : function(record){
9209         var index = this.data.indexOf(record);
9210         this.data.removeAt(index);
9211         if(this.pruneModifiedRecords){
9212             this.modified.remove(record);
9213         }
9214         this.fireEvent("remove", this, record, index);
9215     },
9216
9217     /**
9218      * Remove all Records from the Store and fires the clear event.
9219      */
9220     removeAll : function(){
9221         this.data.clear();
9222         if(this.pruneModifiedRecords){
9223             this.modified = [];
9224         }
9225         this.fireEvent("clear", this);
9226     },
9227
9228     /**
9229      * Inserts Records to the Store at the given index and fires the add event.
9230      * @param {Number} index The start index at which to insert the passed Records.
9231      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9232      */
9233     insert : function(index, records){
9234         records = [].concat(records);
9235         for(var i = 0, len = records.length; i < len; i++){
9236             this.data.insert(index, records[i]);
9237             records[i].join(this);
9238         }
9239         this.fireEvent("add", this, records, index);
9240     },
9241
9242     /**
9243      * Get the index within the cache of the passed Record.
9244      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9245      * @return {Number} The index of the passed Record. Returns -1 if not found.
9246      */
9247     indexOf : function(record){
9248         return this.data.indexOf(record);
9249     },
9250
9251     /**
9252      * Get the index within the cache of the Record with the passed id.
9253      * @param {String} id The id of the Record to find.
9254      * @return {Number} The index of the Record. Returns -1 if not found.
9255      */
9256     indexOfId : function(id){
9257         return this.data.indexOfKey(id);
9258     },
9259
9260     /**
9261      * Get the Record with the specified id.
9262      * @param {String} id The id of the Record to find.
9263      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9264      */
9265     getById : function(id){
9266         return this.data.key(id);
9267     },
9268
9269     /**
9270      * Get the Record at the specified index.
9271      * @param {Number} index The index of the Record to find.
9272      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9273      */
9274     getAt : function(index){
9275         return this.data.itemAt(index);
9276     },
9277
9278     /**
9279      * Returns a range of Records between specified indices.
9280      * @param {Number} startIndex (optional) The starting index (defaults to 0)
9281      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9282      * @return {Roo.data.Record[]} An array of Records
9283      */
9284     getRange : function(start, end){
9285         return this.data.getRange(start, end);
9286     },
9287
9288     // private
9289     storeOptions : function(o){
9290         o = Roo.apply({}, o);
9291         delete o.callback;
9292         delete o.scope;
9293         this.lastOptions = o;
9294     },
9295
9296     /**
9297      * Loads the Record cache from the configured Proxy using the configured Reader.
9298      * <p>
9299      * If using remote paging, then the first load call must specify the <em>start</em>
9300      * and <em>limit</em> properties in the options.params property to establish the initial
9301      * position within the dataset, and the number of Records to cache on each read from the Proxy.
9302      * <p>
9303      * <strong>It is important to note that for remote data sources, loading is asynchronous,
9304      * and this call will return before the new data has been loaded. Perform any post-processing
9305      * in a callback function, or in a "load" event handler.</strong>
9306      * <p>
9307      * @param {Object} options An object containing properties which control loading options:<ul>
9308      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9309      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9310      * passed the following arguments:<ul>
9311      * <li>r : Roo.data.Record[]</li>
9312      * <li>options: Options object from the load call</li>
9313      * <li>success: Boolean success indicator</li></ul></li>
9314      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9315      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9316      * </ul>
9317      */
9318     load : function(options){
9319         options = options || {};
9320         if(this.fireEvent("beforeload", this, options) !== false){
9321             this.storeOptions(options);
9322             var p = Roo.apply(options.params || {}, this.baseParams);
9323             // if meta was not loaded from remote source.. try requesting it.
9324             if (!this.reader.metaFromRemote) {
9325                 p._requestMeta = 1;
9326             }
9327             if(this.sortInfo && this.remoteSort){
9328                 var pn = this.paramNames;
9329                 p[pn["sort"]] = this.sortInfo.field;
9330                 p[pn["dir"]] = this.sortInfo.direction;
9331             }
9332             if (this.multiSort) {
9333                 var pn = this.paramNames;
9334                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9335             }
9336             
9337             this.proxy.load(p, this.reader, this.loadRecords, this, options);
9338         }
9339     },
9340
9341     /**
9342      * Reloads the Record cache from the configured Proxy using the configured Reader and
9343      * the options from the last load operation performed.
9344      * @param {Object} options (optional) An object containing properties which may override the options
9345      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9346      * the most recently used options are reused).
9347      */
9348     reload : function(options){
9349         this.load(Roo.applyIf(options||{}, this.lastOptions));
9350     },
9351
9352     // private
9353     // Called as a callback by the Reader during a load operation.
9354     loadRecords : function(o, options, success){
9355         if(!o || success === false){
9356             if(success !== false){
9357                 this.fireEvent("load", this, [], options, o);
9358             }
9359             if(options.callback){
9360                 options.callback.call(options.scope || this, [], options, false);
9361             }
9362             return;
9363         }
9364         // if data returned failure - throw an exception.
9365         if (o.success === false) {
9366             // show a message if no listener is registered.
9367             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9368                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9369             }
9370             // loadmask wil be hooked into this..
9371             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9372             return;
9373         }
9374         var r = o.records, t = o.totalRecords || r.length;
9375         
9376         this.fireEvent("beforeloadadd", this, r, options, o);
9377         
9378         if(!options || options.add !== true){
9379             if(this.pruneModifiedRecords){
9380                 this.modified = [];
9381             }
9382             for(var i = 0, len = r.length; i < len; i++){
9383                 r[i].join(this);
9384             }
9385             if(this.snapshot){
9386                 this.data = this.snapshot;
9387                 delete this.snapshot;
9388             }
9389             this.data.clear();
9390             this.data.addAll(r);
9391             this.totalLength = t;
9392             this.applySort();
9393             this.fireEvent("datachanged", this);
9394         }else{
9395             this.totalLength = Math.max(t, this.data.length+r.length);
9396             this.add(r);
9397         }
9398         this.fireEvent("load", this, r, options, o);
9399         if(options.callback){
9400             options.callback.call(options.scope || this, r, options, true);
9401         }
9402     },
9403
9404
9405     /**
9406      * Loads data from a passed data block. A Reader which understands the format of the data
9407      * must have been configured in the constructor.
9408      * @param {Object} data The data block from which to read the Records.  The format of the data expected
9409      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9410      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9411      */
9412     loadData : function(o, append){
9413         var r = this.reader.readRecords(o);
9414         this.loadRecords(r, {add: append}, true);
9415     },
9416
9417     /**
9418      * Gets the number of cached records.
9419      * <p>
9420      * <em>If using paging, this may not be the total size of the dataset. If the data object
9421      * used by the Reader contains the dataset size, then the getTotalCount() function returns
9422      * the data set size</em>
9423      */
9424     getCount : function(){
9425         return this.data.length || 0;
9426     },
9427
9428     /**
9429      * Gets the total number of records in the dataset as returned by the server.
9430      * <p>
9431      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9432      * the dataset size</em>
9433      */
9434     getTotalCount : function(){
9435         return this.totalLength || 0;
9436     },
9437
9438     /**
9439      * Returns the sort state of the Store as an object with two properties:
9440      * <pre><code>
9441  field {String} The name of the field by which the Records are sorted
9442  direction {String} The sort order, "ASC" or "DESC"
9443      * </code></pre>
9444      */
9445     getSortState : function(){
9446         return this.sortInfo;
9447     },
9448
9449     // private
9450     applySort : function(){
9451         if(this.sortInfo && !this.remoteSort){
9452             var s = this.sortInfo, f = s.field;
9453             var st = this.fields.get(f).sortType;
9454             var fn = function(r1, r2){
9455                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9456                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9457             };
9458             this.data.sort(s.direction, fn);
9459             if(this.snapshot && this.snapshot != this.data){
9460                 this.snapshot.sort(s.direction, fn);
9461             }
9462         }
9463     },
9464
9465     /**
9466      * Sets the default sort column and order to be used by the next load operation.
9467      * @param {String} fieldName The name of the field to sort by.
9468      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9469      */
9470     setDefaultSort : function(field, dir){
9471         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9472     },
9473
9474     /**
9475      * Sort the Records.
9476      * If remote sorting is used, the sort is performed on the server, and the cache is
9477      * reloaded. If local sorting is used, the cache is sorted internally.
9478      * @param {String} fieldName The name of the field to sort by.
9479      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9480      */
9481     sort : function(fieldName, dir){
9482         var f = this.fields.get(fieldName);
9483         if(!dir){
9484             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9485             
9486             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9487                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9488             }else{
9489                 dir = f.sortDir;
9490             }
9491         }
9492         this.sortToggle[f.name] = dir;
9493         this.sortInfo = {field: f.name, direction: dir};
9494         if(!this.remoteSort){
9495             this.applySort();
9496             this.fireEvent("datachanged", this);
9497         }else{
9498             this.load(this.lastOptions);
9499         }
9500     },
9501
9502     /**
9503      * Calls the specified function for each of the Records in the cache.
9504      * @param {Function} fn The function to call. The Record is passed as the first parameter.
9505      * Returning <em>false</em> aborts and exits the iteration.
9506      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9507      */
9508     each : function(fn, scope){
9509         this.data.each(fn, scope);
9510     },
9511
9512     /**
9513      * Gets all records modified since the last commit.  Modified records are persisted across load operations
9514      * (e.g., during paging).
9515      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9516      */
9517     getModifiedRecords : function(){
9518         return this.modified;
9519     },
9520
9521     // private
9522     createFilterFn : function(property, value, anyMatch){
9523         if(!value.exec){ // not a regex
9524             value = String(value);
9525             if(value.length == 0){
9526                 return false;
9527             }
9528             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9529         }
9530         return function(r){
9531             return value.test(r.data[property]);
9532         };
9533     },
9534
9535     /**
9536      * Sums the value of <i>property</i> for each record between start and end and returns the result.
9537      * @param {String} property A field on your records
9538      * @param {Number} start The record index to start at (defaults to 0)
9539      * @param {Number} end The last record index to include (defaults to length - 1)
9540      * @return {Number} The sum
9541      */
9542     sum : function(property, start, end){
9543         var rs = this.data.items, v = 0;
9544         start = start || 0;
9545         end = (end || end === 0) ? end : rs.length-1;
9546
9547         for(var i = start; i <= end; i++){
9548             v += (rs[i].data[property] || 0);
9549         }
9550         return v;
9551     },
9552
9553     /**
9554      * Filter the records by a specified property.
9555      * @param {String} field A field on your records
9556      * @param {String/RegExp} value Either a string that the field
9557      * should start with or a RegExp to test against the field
9558      * @param {Boolean} anyMatch True to match any part not just the beginning
9559      */
9560     filter : function(property, value, anyMatch){
9561         var fn = this.createFilterFn(property, value, anyMatch);
9562         return fn ? this.filterBy(fn) : this.clearFilter();
9563     },
9564
9565     /**
9566      * Filter by a function. The specified function will be called with each
9567      * record in this data source. If the function returns true the record is included,
9568      * otherwise it is filtered.
9569      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9570      * @param {Object} scope (optional) The scope of the function (defaults to this)
9571      */
9572     filterBy : function(fn, scope){
9573         this.snapshot = this.snapshot || this.data;
9574         this.data = this.queryBy(fn, scope||this);
9575         this.fireEvent("datachanged", this);
9576     },
9577
9578     /**
9579      * Query the records by a specified property.
9580      * @param {String} field A field on your records
9581      * @param {String/RegExp} value Either a string that the field
9582      * should start with or a RegExp to test against the field
9583      * @param {Boolean} anyMatch True to match any part not just the beginning
9584      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9585      */
9586     query : function(property, value, anyMatch){
9587         var fn = this.createFilterFn(property, value, anyMatch);
9588         return fn ? this.queryBy(fn) : this.data.clone();
9589     },
9590
9591     /**
9592      * Query by a function. The specified function will be called with each
9593      * record in this data source. If the function returns true the record is included
9594      * in the results.
9595      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9596      * @param {Object} scope (optional) The scope of the function (defaults to this)
9597       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9598      **/
9599     queryBy : function(fn, scope){
9600         var data = this.snapshot || this.data;
9601         return data.filterBy(fn, scope||this);
9602     },
9603
9604     /**
9605      * Collects unique values for a particular dataIndex from this store.
9606      * @param {String} dataIndex The property to collect
9607      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9608      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9609      * @return {Array} An array of the unique values
9610      **/
9611     collect : function(dataIndex, allowNull, bypassFilter){
9612         var d = (bypassFilter === true && this.snapshot) ?
9613                 this.snapshot.items : this.data.items;
9614         var v, sv, r = [], l = {};
9615         for(var i = 0, len = d.length; i < len; i++){
9616             v = d[i].data[dataIndex];
9617             sv = String(v);
9618             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9619                 l[sv] = true;
9620                 r[r.length] = v;
9621             }
9622         }
9623         return r;
9624     },
9625
9626     /**
9627      * Revert to a view of the Record cache with no filtering applied.
9628      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9629      */
9630     clearFilter : function(suppressEvent){
9631         if(this.snapshot && this.snapshot != this.data){
9632             this.data = this.snapshot;
9633             delete this.snapshot;
9634             if(suppressEvent !== true){
9635                 this.fireEvent("datachanged", this);
9636             }
9637         }
9638     },
9639
9640     // private
9641     afterEdit : function(record){
9642         if(this.modified.indexOf(record) == -1){
9643             this.modified.push(record);
9644         }
9645         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9646     },
9647     
9648     // private
9649     afterReject : function(record){
9650         this.modified.remove(record);
9651         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9652     },
9653
9654     // private
9655     afterCommit : function(record){
9656         this.modified.remove(record);
9657         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9658     },
9659
9660     /**
9661      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9662      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9663      */
9664     commitChanges : function(){
9665         var m = this.modified.slice(0);
9666         this.modified = [];
9667         for(var i = 0, len = m.length; i < len; i++){
9668             m[i].commit();
9669         }
9670     },
9671
9672     /**
9673      * Cancel outstanding changes on all changed records.
9674      */
9675     rejectChanges : function(){
9676         var m = this.modified.slice(0);
9677         this.modified = [];
9678         for(var i = 0, len = m.length; i < len; i++){
9679             m[i].reject();
9680         }
9681     },
9682
9683     onMetaChange : function(meta, rtype, o){
9684         this.recordType = rtype;
9685         this.fields = rtype.prototype.fields;
9686         delete this.snapshot;
9687         this.sortInfo = meta.sortInfo || this.sortInfo;
9688         this.modified = [];
9689         this.fireEvent('metachange', this, this.reader.meta);
9690     },
9691     
9692     moveIndex : function(data, type)
9693     {
9694         var index = this.indexOf(data);
9695         
9696         var newIndex = index + type;
9697         
9698         this.remove(data);
9699         
9700         this.insert(newIndex, data);
9701         
9702     }
9703 });/*
9704  * Based on:
9705  * Ext JS Library 1.1.1
9706  * Copyright(c) 2006-2007, Ext JS, LLC.
9707  *
9708  * Originally Released Under LGPL - original licence link has changed is not relivant.
9709  *
9710  * Fork - LGPL
9711  * <script type="text/javascript">
9712  */
9713
9714 /**
9715  * @class Roo.data.SimpleStore
9716  * @extends Roo.data.Store
9717  * Small helper class to make creating Stores from Array data easier.
9718  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9719  * @cfg {Array} fields An array of field definition objects, or field name strings.
9720  * @cfg {Array} data The multi-dimensional array of data
9721  * @constructor
9722  * @param {Object} config
9723  */
9724 Roo.data.SimpleStore = function(config){
9725     Roo.data.SimpleStore.superclass.constructor.call(this, {
9726         isLocal : true,
9727         reader: new Roo.data.ArrayReader({
9728                 id: config.id
9729             },
9730             Roo.data.Record.create(config.fields)
9731         ),
9732         proxy : new Roo.data.MemoryProxy(config.data)
9733     });
9734     this.load();
9735 };
9736 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9737  * Based on:
9738  * Ext JS Library 1.1.1
9739  * Copyright(c) 2006-2007, Ext JS, LLC.
9740  *
9741  * Originally Released Under LGPL - original licence link has changed is not relivant.
9742  *
9743  * Fork - LGPL
9744  * <script type="text/javascript">
9745  */
9746
9747 /**
9748 /**
9749  * @extends Roo.data.Store
9750  * @class Roo.data.JsonStore
9751  * Small helper class to make creating Stores for JSON data easier. <br/>
9752 <pre><code>
9753 var store = new Roo.data.JsonStore({
9754     url: 'get-images.php',
9755     root: 'images',
9756     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9757 });
9758 </code></pre>
9759  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9760  * JsonReader and HttpProxy (unless inline data is provided).</b>
9761  * @cfg {Array} fields An array of field definition objects, or field name strings.
9762  * @constructor
9763  * @param {Object} config
9764  */
9765 Roo.data.JsonStore = function(c){
9766     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9767         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9768         reader: new Roo.data.JsonReader(c, c.fields)
9769     }));
9770 };
9771 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9772  * Based on:
9773  * Ext JS Library 1.1.1
9774  * Copyright(c) 2006-2007, Ext JS, LLC.
9775  *
9776  * Originally Released Under LGPL - original licence link has changed is not relivant.
9777  *
9778  * Fork - LGPL
9779  * <script type="text/javascript">
9780  */
9781
9782  
9783 Roo.data.Field = function(config){
9784     if(typeof config == "string"){
9785         config = {name: config};
9786     }
9787     Roo.apply(this, config);
9788     
9789     if(!this.type){
9790         this.type = "auto";
9791     }
9792     
9793     var st = Roo.data.SortTypes;
9794     // named sortTypes are supported, here we look them up
9795     if(typeof this.sortType == "string"){
9796         this.sortType = st[this.sortType];
9797     }
9798     
9799     // set default sortType for strings and dates
9800     if(!this.sortType){
9801         switch(this.type){
9802             case "string":
9803                 this.sortType = st.asUCString;
9804                 break;
9805             case "date":
9806                 this.sortType = st.asDate;
9807                 break;
9808             default:
9809                 this.sortType = st.none;
9810         }
9811     }
9812
9813     // define once
9814     var stripRe = /[\$,%]/g;
9815
9816     // prebuilt conversion function for this field, instead of
9817     // switching every time we're reading a value
9818     if(!this.convert){
9819         var cv, dateFormat = this.dateFormat;
9820         switch(this.type){
9821             case "":
9822             case "auto":
9823             case undefined:
9824                 cv = function(v){ return v; };
9825                 break;
9826             case "string":
9827                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
9828                 break;
9829             case "int":
9830                 cv = function(v){
9831                     return v !== undefined && v !== null && v !== '' ?
9832                            parseInt(String(v).replace(stripRe, ""), 10) : '';
9833                     };
9834                 break;
9835             case "float":
9836                 cv = function(v){
9837                     return v !== undefined && v !== null && v !== '' ?
9838                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
9839                     };
9840                 break;
9841             case "bool":
9842             case "boolean":
9843                 cv = function(v){ return v === true || v === "true" || v == 1; };
9844                 break;
9845             case "date":
9846                 cv = function(v){
9847                     if(!v){
9848                         return '';
9849                     }
9850                     if(v instanceof Date){
9851                         return v;
9852                     }
9853                     if(dateFormat){
9854                         if(dateFormat == "timestamp"){
9855                             return new Date(v*1000);
9856                         }
9857                         return Date.parseDate(v, dateFormat);
9858                     }
9859                     var parsed = Date.parse(v);
9860                     return parsed ? new Date(parsed) : null;
9861                 };
9862              break;
9863             
9864         }
9865         this.convert = cv;
9866     }
9867 };
9868
9869 Roo.data.Field.prototype = {
9870     dateFormat: null,
9871     defaultValue: "",
9872     mapping: null,
9873     sortType : null,
9874     sortDir : "ASC"
9875 };/*
9876  * Based on:
9877  * Ext JS Library 1.1.1
9878  * Copyright(c) 2006-2007, Ext JS, LLC.
9879  *
9880  * Originally Released Under LGPL - original licence link has changed is not relivant.
9881  *
9882  * Fork - LGPL
9883  * <script type="text/javascript">
9884  */
9885  
9886 // Base class for reading structured data from a data source.  This class is intended to be
9887 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
9888
9889 /**
9890  * @class Roo.data.DataReader
9891  * Base class for reading structured data from a data source.  This class is intended to be
9892  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
9893  */
9894
9895 Roo.data.DataReader = function(meta, recordType){
9896     
9897     this.meta = meta;
9898     
9899     this.recordType = recordType instanceof Array ? 
9900         Roo.data.Record.create(recordType) : recordType;
9901 };
9902
9903 Roo.data.DataReader.prototype = {
9904      /**
9905      * Create an empty record
9906      * @param {Object} data (optional) - overlay some values
9907      * @return {Roo.data.Record} record created.
9908      */
9909     newRow :  function(d) {
9910         var da =  {};
9911         this.recordType.prototype.fields.each(function(c) {
9912             switch( c.type) {
9913                 case 'int' : da[c.name] = 0; break;
9914                 case 'date' : da[c.name] = new Date(); break;
9915                 case 'float' : da[c.name] = 0.0; break;
9916                 case 'boolean' : da[c.name] = false; break;
9917                 default : da[c.name] = ""; break;
9918             }
9919             
9920         });
9921         return new this.recordType(Roo.apply(da, d));
9922     }
9923     
9924 };/*
9925  * Based on:
9926  * Ext JS Library 1.1.1
9927  * Copyright(c) 2006-2007, Ext JS, LLC.
9928  *
9929  * Originally Released Under LGPL - original licence link has changed is not relivant.
9930  *
9931  * Fork - LGPL
9932  * <script type="text/javascript">
9933  */
9934
9935 /**
9936  * @class Roo.data.DataProxy
9937  * @extends Roo.data.Observable
9938  * This class is an abstract base class for implementations which provide retrieval of
9939  * unformatted data objects.<br>
9940  * <p>
9941  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
9942  * (of the appropriate type which knows how to parse the data object) to provide a block of
9943  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
9944  * <p>
9945  * Custom implementations must implement the load method as described in
9946  * {@link Roo.data.HttpProxy#load}.
9947  */
9948 Roo.data.DataProxy = function(){
9949     this.addEvents({
9950         /**
9951          * @event beforeload
9952          * Fires before a network request is made to retrieve a data object.
9953          * @param {Object} This DataProxy object.
9954          * @param {Object} params The params parameter to the load function.
9955          */
9956         beforeload : true,
9957         /**
9958          * @event load
9959          * Fires before the load method's callback is called.
9960          * @param {Object} This DataProxy object.
9961          * @param {Object} o The data object.
9962          * @param {Object} arg The callback argument object passed to the load function.
9963          */
9964         load : true,
9965         /**
9966          * @event loadexception
9967          * Fires if an Exception occurs during data retrieval.
9968          * @param {Object} This DataProxy object.
9969          * @param {Object} o The data object.
9970          * @param {Object} arg The callback argument object passed to the load function.
9971          * @param {Object} e The Exception.
9972          */
9973         loadexception : true
9974     });
9975     Roo.data.DataProxy.superclass.constructor.call(this);
9976 };
9977
9978 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9979
9980     /**
9981      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9982      */
9983 /*
9984  * Based on:
9985  * Ext JS Library 1.1.1
9986  * Copyright(c) 2006-2007, Ext JS, LLC.
9987  *
9988  * Originally Released Under LGPL - original licence link has changed is not relivant.
9989  *
9990  * Fork - LGPL
9991  * <script type="text/javascript">
9992  */
9993 /**
9994  * @class Roo.data.MemoryProxy
9995  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9996  * to the Reader when its load method is called.
9997  * @constructor
9998  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9999  */
10000 Roo.data.MemoryProxy = function(data){
10001     if (data.data) {
10002         data = data.data;
10003     }
10004     Roo.data.MemoryProxy.superclass.constructor.call(this);
10005     this.data = data;
10006 };
10007
10008 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10009     /**
10010      * Load data from the requested source (in this case an in-memory
10011      * data object passed to the constructor), read the data object into
10012      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10013      * process that block using the passed callback.
10014      * @param {Object} params This parameter is not used by the MemoryProxy class.
10015      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10016      * object into a block of Roo.data.Records.
10017      * @param {Function} callback The function into which to pass the block of Roo.data.records.
10018      * The function must be passed <ul>
10019      * <li>The Record block object</li>
10020      * <li>The "arg" argument from the load function</li>
10021      * <li>A boolean success indicator</li>
10022      * </ul>
10023      * @param {Object} scope The scope in which to call the callback
10024      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10025      */
10026     load : function(params, reader, callback, scope, arg){
10027         params = params || {};
10028         var result;
10029         try {
10030             result = reader.readRecords(this.data);
10031         }catch(e){
10032             this.fireEvent("loadexception", this, arg, null, e);
10033             callback.call(scope, null, arg, false);
10034             return;
10035         }
10036         callback.call(scope, result, arg, true);
10037     },
10038     
10039     // private
10040     update : function(params, records){
10041         
10042     }
10043 });/*
10044  * Based on:
10045  * Ext JS Library 1.1.1
10046  * Copyright(c) 2006-2007, Ext JS, LLC.
10047  *
10048  * Originally Released Under LGPL - original licence link has changed is not relivant.
10049  *
10050  * Fork - LGPL
10051  * <script type="text/javascript">
10052  */
10053 /**
10054  * @class Roo.data.HttpProxy
10055  * @extends Roo.data.DataProxy
10056  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10057  * configured to reference a certain URL.<br><br>
10058  * <p>
10059  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10060  * from which the running page was served.<br><br>
10061  * <p>
10062  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10063  * <p>
10064  * Be aware that to enable the browser to parse an XML document, the server must set
10065  * the Content-Type header in the HTTP response to "text/xml".
10066  * @constructor
10067  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10068  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
10069  * will be used to make the request.
10070  */
10071 Roo.data.HttpProxy = function(conn){
10072     Roo.data.HttpProxy.superclass.constructor.call(this);
10073     // is conn a conn config or a real conn?
10074     this.conn = conn;
10075     this.useAjax = !conn || !conn.events;
10076   
10077 };
10078
10079 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10080     // thse are take from connection...
10081     
10082     /**
10083      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10084      */
10085     /**
10086      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10087      * extra parameters to each request made by this object. (defaults to undefined)
10088      */
10089     /**
10090      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10091      *  to each request made by this object. (defaults to undefined)
10092      */
10093     /**
10094      * @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)
10095      */
10096     /**
10097      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10098      */
10099      /**
10100      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10101      * @type Boolean
10102      */
10103   
10104
10105     /**
10106      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10107      * @type Boolean
10108      */
10109     /**
10110      * Return the {@link Roo.data.Connection} object being used by this Proxy.
10111      * @return {Connection} The Connection object. This object may be used to subscribe to events on
10112      * a finer-grained basis than the DataProxy events.
10113      */
10114     getConnection : function(){
10115         return this.useAjax ? Roo.Ajax : this.conn;
10116     },
10117
10118     /**
10119      * Load data from the configured {@link Roo.data.Connection}, read the data object into
10120      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10121      * process that block using the passed callback.
10122      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10123      * for the request to the remote server.
10124      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10125      * object into a block of Roo.data.Records.
10126      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10127      * The function must be passed <ul>
10128      * <li>The Record block object</li>
10129      * <li>The "arg" argument from the load function</li>
10130      * <li>A boolean success indicator</li>
10131      * </ul>
10132      * @param {Object} scope The scope in which to call the callback
10133      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10134      */
10135     load : function(params, reader, callback, scope, arg){
10136         if(this.fireEvent("beforeload", this, params) !== false){
10137             var  o = {
10138                 params : params || {},
10139                 request: {
10140                     callback : callback,
10141                     scope : scope,
10142                     arg : arg
10143                 },
10144                 reader: reader,
10145                 callback : this.loadResponse,
10146                 scope: this
10147             };
10148             if(this.useAjax){
10149                 Roo.applyIf(o, this.conn);
10150                 if(this.activeRequest){
10151                     Roo.Ajax.abort(this.activeRequest);
10152                 }
10153                 this.activeRequest = Roo.Ajax.request(o);
10154             }else{
10155                 this.conn.request(o);
10156             }
10157         }else{
10158             callback.call(scope||this, null, arg, false);
10159         }
10160     },
10161
10162     // private
10163     loadResponse : function(o, success, response){
10164         delete this.activeRequest;
10165         if(!success){
10166             this.fireEvent("loadexception", this, o, response);
10167             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10168             return;
10169         }
10170         var result;
10171         try {
10172             result = o.reader.read(response);
10173         }catch(e){
10174             this.fireEvent("loadexception", this, o, response, e);
10175             o.request.callback.call(o.request.scope, null, o.request.arg, false);
10176             return;
10177         }
10178         
10179         this.fireEvent("load", this, o, o.request.arg);
10180         o.request.callback.call(o.request.scope, result, o.request.arg, true);
10181     },
10182
10183     // private
10184     update : function(dataSet){
10185
10186     },
10187
10188     // private
10189     updateResponse : function(dataSet){
10190
10191     }
10192 });/*
10193  * Based on:
10194  * Ext JS Library 1.1.1
10195  * Copyright(c) 2006-2007, Ext JS, LLC.
10196  *
10197  * Originally Released Under LGPL - original licence link has changed is not relivant.
10198  *
10199  * Fork - LGPL
10200  * <script type="text/javascript">
10201  */
10202
10203 /**
10204  * @class Roo.data.ScriptTagProxy
10205  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10206  * other than the originating domain of the running page.<br><br>
10207  * <p>
10208  * <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
10209  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10210  * <p>
10211  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10212  * source code that is used as the source inside a &lt;script> tag.<br><br>
10213  * <p>
10214  * In order for the browser to process the returned data, the server must wrap the data object
10215  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10216  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10217  * depending on whether the callback name was passed:
10218  * <p>
10219  * <pre><code>
10220 boolean scriptTag = false;
10221 String cb = request.getParameter("callback");
10222 if (cb != null) {
10223     scriptTag = true;
10224     response.setContentType("text/javascript");
10225 } else {
10226     response.setContentType("application/x-json");
10227 }
10228 Writer out = response.getWriter();
10229 if (scriptTag) {
10230     out.write(cb + "(");
10231 }
10232 out.print(dataBlock.toJsonString());
10233 if (scriptTag) {
10234     out.write(");");
10235 }
10236 </pre></code>
10237  *
10238  * @constructor
10239  * @param {Object} config A configuration object.
10240  */
10241 Roo.data.ScriptTagProxy = function(config){
10242     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10243     Roo.apply(this, config);
10244     this.head = document.getElementsByTagName("head")[0];
10245 };
10246
10247 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10248
10249 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10250     /**
10251      * @cfg {String} url The URL from which to request the data object.
10252      */
10253     /**
10254      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10255      */
10256     timeout : 30000,
10257     /**
10258      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10259      * the server the name of the callback function set up by the load call to process the returned data object.
10260      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10261      * javascript output which calls this named function passing the data object as its only parameter.
10262      */
10263     callbackParam : "callback",
10264     /**
10265      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10266      * name to the request.
10267      */
10268     nocache : true,
10269
10270     /**
10271      * Load data from the configured URL, read the data object into
10272      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10273      * process that block using the passed callback.
10274      * @param {Object} params An object containing properties which are to be used as HTTP parameters
10275      * for the request to the remote server.
10276      * @param {Roo.data.DataReader} reader The Reader object which converts the data
10277      * object into a block of Roo.data.Records.
10278      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10279      * The function must be passed <ul>
10280      * <li>The Record block object</li>
10281      * <li>The "arg" argument from the load function</li>
10282      * <li>A boolean success indicator</li>
10283      * </ul>
10284      * @param {Object} scope The scope in which to call the callback
10285      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10286      */
10287     load : function(params, reader, callback, scope, arg){
10288         if(this.fireEvent("beforeload", this, params) !== false){
10289
10290             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10291
10292             var url = this.url;
10293             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10294             if(this.nocache){
10295                 url += "&_dc=" + (new Date().getTime());
10296             }
10297             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10298             var trans = {
10299                 id : transId,
10300                 cb : "stcCallback"+transId,
10301                 scriptId : "stcScript"+transId,
10302                 params : params,
10303                 arg : arg,
10304                 url : url,
10305                 callback : callback,
10306                 scope : scope,
10307                 reader : reader
10308             };
10309             var conn = this;
10310
10311             window[trans.cb] = function(o){
10312                 conn.handleResponse(o, trans);
10313             };
10314
10315             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10316
10317             if(this.autoAbort !== false){
10318                 this.abort();
10319             }
10320
10321             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10322
10323             var script = document.createElement("script");
10324             script.setAttribute("src", url);
10325             script.setAttribute("type", "text/javascript");
10326             script.setAttribute("id", trans.scriptId);
10327             this.head.appendChild(script);
10328
10329             this.trans = trans;
10330         }else{
10331             callback.call(scope||this, null, arg, false);
10332         }
10333     },
10334
10335     // private
10336     isLoading : function(){
10337         return this.trans ? true : false;
10338     },
10339
10340     /**
10341      * Abort the current server request.
10342      */
10343     abort : function(){
10344         if(this.isLoading()){
10345             this.destroyTrans(this.trans);
10346         }
10347     },
10348
10349     // private
10350     destroyTrans : function(trans, isLoaded){
10351         this.head.removeChild(document.getElementById(trans.scriptId));
10352         clearTimeout(trans.timeoutId);
10353         if(isLoaded){
10354             window[trans.cb] = undefined;
10355             try{
10356                 delete window[trans.cb];
10357             }catch(e){}
10358         }else{
10359             // if hasn't been loaded, wait for load to remove it to prevent script error
10360             window[trans.cb] = function(){
10361                 window[trans.cb] = undefined;
10362                 try{
10363                     delete window[trans.cb];
10364                 }catch(e){}
10365             };
10366         }
10367     },
10368
10369     // private
10370     handleResponse : function(o, trans){
10371         this.trans = false;
10372         this.destroyTrans(trans, true);
10373         var result;
10374         try {
10375             result = trans.reader.readRecords(o);
10376         }catch(e){
10377             this.fireEvent("loadexception", this, o, trans.arg, e);
10378             trans.callback.call(trans.scope||window, null, trans.arg, false);
10379             return;
10380         }
10381         this.fireEvent("load", this, o, trans.arg);
10382         trans.callback.call(trans.scope||window, result, trans.arg, true);
10383     },
10384
10385     // private
10386     handleFailure : function(trans){
10387         this.trans = false;
10388         this.destroyTrans(trans, false);
10389         this.fireEvent("loadexception", this, null, trans.arg);
10390         trans.callback.call(trans.scope||window, null, trans.arg, false);
10391     }
10392 });/*
10393  * Based on:
10394  * Ext JS Library 1.1.1
10395  * Copyright(c) 2006-2007, Ext JS, LLC.
10396  *
10397  * Originally Released Under LGPL - original licence link has changed is not relivant.
10398  *
10399  * Fork - LGPL
10400  * <script type="text/javascript">
10401  */
10402
10403 /**
10404  * @class Roo.data.JsonReader
10405  * @extends Roo.data.DataReader
10406  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10407  * based on mappings in a provided Roo.data.Record constructor.
10408  * 
10409  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10410  * in the reply previously. 
10411  * 
10412  * <p>
10413  * Example code:
10414  * <pre><code>
10415 var RecordDef = Roo.data.Record.create([
10416     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
10417     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
10418 ]);
10419 var myReader = new Roo.data.JsonReader({
10420     totalProperty: "results",    // The property which contains the total dataset size (optional)
10421     root: "rows",                // The property which contains an Array of row objects
10422     id: "id"                     // The property within each row object that provides an ID for the record (optional)
10423 }, RecordDef);
10424 </code></pre>
10425  * <p>
10426  * This would consume a JSON file like this:
10427  * <pre><code>
10428 { 'results': 2, 'rows': [
10429     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10430     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10431 }
10432 </code></pre>
10433  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10434  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10435  * paged from the remote server.
10436  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10437  * @cfg {String} root name of the property which contains the Array of row objects.
10438  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10439  * @constructor
10440  * Create a new JsonReader
10441  * @param {Object} meta Metadata configuration options
10442  * @param {Object} recordType Either an Array of field definition objects,
10443  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10444  */
10445 Roo.data.JsonReader = function(meta, recordType){
10446     
10447     meta = meta || {};
10448     // set some defaults:
10449     Roo.applyIf(meta, {
10450         totalProperty: 'total',
10451         successProperty : 'success',
10452         root : 'data',
10453         id : 'id'
10454     });
10455     
10456     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10457 };
10458 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10459     
10460     /**
10461      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
10462      * Used by Store query builder to append _requestMeta to params.
10463      * 
10464      */
10465     metaFromRemote : false,
10466     /**
10467      * This method is only used by a DataProxy which has retrieved data from a remote server.
10468      * @param {Object} response The XHR object which contains the JSON data in its responseText.
10469      * @return {Object} data A data block which is used by an Roo.data.Store object as
10470      * a cache of Roo.data.Records.
10471      */
10472     read : function(response){
10473         var json = response.responseText;
10474        
10475         var o = /* eval:var:o */ eval("("+json+")");
10476         if(!o) {
10477             throw {message: "JsonReader.read: Json object not found"};
10478         }
10479         
10480         if(o.metaData){
10481             
10482             delete this.ef;
10483             this.metaFromRemote = true;
10484             this.meta = o.metaData;
10485             this.recordType = Roo.data.Record.create(o.metaData.fields);
10486             this.onMetaChange(this.meta, this.recordType, o);
10487         }
10488         return this.readRecords(o);
10489     },
10490
10491     // private function a store will implement
10492     onMetaChange : function(meta, recordType, o){
10493
10494     },
10495
10496     /**
10497          * @ignore
10498          */
10499     simpleAccess: function(obj, subsc) {
10500         return obj[subsc];
10501     },
10502
10503         /**
10504          * @ignore
10505          */
10506     getJsonAccessor: function(){
10507         var re = /[\[\.]/;
10508         return function(expr) {
10509             try {
10510                 return(re.test(expr))
10511                     ? new Function("obj", "return obj." + expr)
10512                     : function(obj){
10513                         return obj[expr];
10514                     };
10515             } catch(e){}
10516             return Roo.emptyFn;
10517         };
10518     }(),
10519
10520     /**
10521      * Create a data block containing Roo.data.Records from an XML document.
10522      * @param {Object} o An object which contains an Array of row objects in the property specified
10523      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10524      * which contains the total size of the dataset.
10525      * @return {Object} data A data block which is used by an Roo.data.Store object as
10526      * a cache of Roo.data.Records.
10527      */
10528     readRecords : function(o){
10529         /**
10530          * After any data loads, the raw JSON data is available for further custom processing.
10531          * @type Object
10532          */
10533         this.o = o;
10534         var s = this.meta, Record = this.recordType,
10535             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10536
10537 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
10538         if (!this.ef) {
10539             if(s.totalProperty) {
10540                     this.getTotal = this.getJsonAccessor(s.totalProperty);
10541                 }
10542                 if(s.successProperty) {
10543                     this.getSuccess = this.getJsonAccessor(s.successProperty);
10544                 }
10545                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10546                 if (s.id) {
10547                         var g = this.getJsonAccessor(s.id);
10548                         this.getId = function(rec) {
10549                                 var r = g(rec);  
10550                                 return (r === undefined || r === "") ? null : r;
10551                         };
10552                 } else {
10553                         this.getId = function(){return null;};
10554                 }
10555             this.ef = [];
10556             for(var jj = 0; jj < fl; jj++){
10557                 f = fi[jj];
10558                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10559                 this.ef[jj] = this.getJsonAccessor(map);
10560             }
10561         }
10562
10563         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10564         if(s.totalProperty){
10565             var vt = parseInt(this.getTotal(o), 10);
10566             if(!isNaN(vt)){
10567                 totalRecords = vt;
10568             }
10569         }
10570         if(s.successProperty){
10571             var vs = this.getSuccess(o);
10572             if(vs === false || vs === 'false'){
10573                 success = false;
10574             }
10575         }
10576         var records = [];
10577         for(var i = 0; i < c; i++){
10578                 var n = root[i];
10579             var values = {};
10580             var id = this.getId(n);
10581             for(var j = 0; j < fl; j++){
10582                 f = fi[j];
10583             var v = this.ef[j](n);
10584             if (!f.convert) {
10585                 Roo.log('missing convert for ' + f.name);
10586                 Roo.log(f);
10587                 continue;
10588             }
10589             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10590             }
10591             var record = new Record(values, id);
10592             record.json = n;
10593             records[i] = record;
10594         }
10595         return {
10596             raw : o,
10597             success : success,
10598             records : records,
10599             totalRecords : totalRecords
10600         };
10601     }
10602 });/*
10603  * Based on:
10604  * Ext JS Library 1.1.1
10605  * Copyright(c) 2006-2007, Ext JS, LLC.
10606  *
10607  * Originally Released Under LGPL - original licence link has changed is not relivant.
10608  *
10609  * Fork - LGPL
10610  * <script type="text/javascript">
10611  */
10612
10613 /**
10614  * @class Roo.data.ArrayReader
10615  * @extends Roo.data.DataReader
10616  * Data reader class to create an Array of Roo.data.Record objects from an Array.
10617  * Each element of that Array represents a row of data fields. The
10618  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10619  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10620  * <p>
10621  * Example code:.
10622  * <pre><code>
10623 var RecordDef = Roo.data.Record.create([
10624     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
10625     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
10626 ]);
10627 var myReader = new Roo.data.ArrayReader({
10628     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
10629 }, RecordDef);
10630 </code></pre>
10631  * <p>
10632  * This would consume an Array like this:
10633  * <pre><code>
10634 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10635   </code></pre>
10636  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10637  * @constructor
10638  * Create a new JsonReader
10639  * @param {Object} meta Metadata configuration options.
10640  * @param {Object} recordType Either an Array of field definition objects
10641  * as specified to {@link Roo.data.Record#create},
10642  * or an {@link Roo.data.Record} object
10643  * created using {@link Roo.data.Record#create}.
10644  */
10645 Roo.data.ArrayReader = function(meta, recordType){
10646     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10647 };
10648
10649 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10650     /**
10651      * Create a data block containing Roo.data.Records from an XML document.
10652      * @param {Object} o An Array of row objects which represents the dataset.
10653      * @return {Object} data A data block which is used by an Roo.data.Store object as
10654      * a cache of Roo.data.Records.
10655      */
10656     readRecords : function(o){
10657         var sid = this.meta ? this.meta.id : null;
10658         var recordType = this.recordType, fields = recordType.prototype.fields;
10659         var records = [];
10660         var root = o;
10661             for(var i = 0; i < root.length; i++){
10662                     var n = root[i];
10663                 var values = {};
10664                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10665                 for(var j = 0, jlen = fields.length; j < jlen; j++){
10666                 var f = fields.items[j];
10667                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10668                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10669                 v = f.convert(v);
10670                 values[f.name] = v;
10671             }
10672                 var record = new recordType(values, id);
10673                 record.json = n;
10674                 records[records.length] = record;
10675             }
10676             return {
10677                 records : records,
10678                 totalRecords : records.length
10679             };
10680     }
10681 });/*
10682  * - LGPL
10683  * * 
10684  */
10685
10686 /**
10687  * @class Roo.bootstrap.ComboBox
10688  * @extends Roo.bootstrap.TriggerField
10689  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10690  * @cfg {Boolean} append (true|false) default false
10691  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10692  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10693  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10694  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10695  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10696  * @constructor
10697  * Create a new ComboBox.
10698  * @param {Object} config Configuration options
10699  */
10700 Roo.bootstrap.ComboBox = function(config){
10701     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10702     this.addEvents({
10703         /**
10704          * @event expand
10705          * Fires when the dropdown list is expanded
10706              * @param {Roo.bootstrap.ComboBox} combo This combo box
10707              */
10708         'expand' : true,
10709         /**
10710          * @event collapse
10711          * Fires when the dropdown list is collapsed
10712              * @param {Roo.bootstrap.ComboBox} combo This combo box
10713              */
10714         'collapse' : true,
10715         /**
10716          * @event beforeselect
10717          * Fires before a list item is selected. Return false to cancel the selection.
10718              * @param {Roo.bootstrap.ComboBox} combo This combo box
10719              * @param {Roo.data.Record} record The data record returned from the underlying store
10720              * @param {Number} index The index of the selected item in the dropdown list
10721              */
10722         'beforeselect' : true,
10723         /**
10724          * @event select
10725          * Fires when a list item is selected
10726              * @param {Roo.bootstrap.ComboBox} combo This combo box
10727              * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10728              * @param {Number} index The index of the selected item in the dropdown list
10729              */
10730         'select' : true,
10731         /**
10732          * @event beforequery
10733          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10734          * The event object passed has these properties:
10735              * @param {Roo.bootstrap.ComboBox} combo This combo box
10736              * @param {String} query The query
10737              * @param {Boolean} forceAll true to force "all" query
10738              * @param {Boolean} cancel true to cancel the query
10739              * @param {Object} e The query event object
10740              */
10741         'beforequery': true,
10742          /**
10743          * @event add
10744          * Fires when the 'add' icon is pressed (add a listener to enable add button)
10745              * @param {Roo.bootstrap.ComboBox} combo This combo box
10746              */
10747         'add' : true,
10748         /**
10749          * @event edit
10750          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10751              * @param {Roo.bootstrap.ComboBox} combo This combo box
10752              * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10753              */
10754         'edit' : true,
10755         /**
10756          * @event remove
10757          * Fires when the remove value from the combobox array
10758              * @param {Roo.bootstrap.ComboBox} combo This combo box
10759              */
10760         'remove' : true
10761         
10762     });
10763     
10764     this.item = [];
10765     this.tickItems = [];
10766     
10767     this.selectedIndex = -1;
10768     if(this.mode == 'local'){
10769         if(config.queryDelay === undefined){
10770             this.queryDelay = 10;
10771         }
10772         if(config.minChars === undefined){
10773             this.minChars = 0;
10774         }
10775     }
10776 };
10777
10778 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10779      
10780     /**
10781      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10782      * rendering into an Roo.Editor, defaults to false)
10783      */
10784     /**
10785      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10786      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10787      */
10788     /**
10789      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10790      */
10791     /**
10792      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10793      * the dropdown list (defaults to undefined, with no header element)
10794      */
10795
10796      /**
10797      * @cfg {String/Roo.Template} tpl The template to use to render the output
10798      */
10799      
10800      /**
10801      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10802      */
10803     listWidth: undefined,
10804     /**
10805      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10806      * mode = 'remote' or 'text' if mode = 'local')
10807      */
10808     displayField: undefined,
10809     /**
10810      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10811      * mode = 'remote' or 'value' if mode = 'local'). 
10812      * Note: use of a valueField requires the user make a selection
10813      * in order for a value to be mapped.
10814      */
10815     valueField: undefined,
10816     
10817     
10818     /**
10819      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
10820      * field's data value (defaults to the underlying DOM element's name)
10821      */
10822     hiddenName: undefined,
10823     /**
10824      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
10825      */
10826     listClass: '',
10827     /**
10828      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
10829      */
10830     selectedClass: 'active',
10831     
10832     /**
10833      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
10834      */
10835     shadow:'sides',
10836     /**
10837      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
10838      * anchor positions (defaults to 'tl-bl')
10839      */
10840     listAlign: 'tl-bl?',
10841     /**
10842      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
10843      */
10844     maxHeight: 300,
10845     /**
10846      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
10847      * query specified by the allQuery config option (defaults to 'query')
10848      */
10849     triggerAction: 'query',
10850     /**
10851      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
10852      * (defaults to 4, does not apply if editable = false)
10853      */
10854     minChars : 4,
10855     /**
10856      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
10857      * delay (typeAheadDelay) if it matches a known value (defaults to false)
10858      */
10859     typeAhead: false,
10860     /**
10861      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
10862      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
10863      */
10864     queryDelay: 500,
10865     /**
10866      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
10867      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
10868      */
10869     pageSize: 0,
10870     /**
10871      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
10872      * when editable = true (defaults to false)
10873      */
10874     selectOnFocus:false,
10875     /**
10876      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
10877      */
10878     queryParam: 'query',
10879     /**
10880      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
10881      * when mode = 'remote' (defaults to 'Loading...')
10882      */
10883     loadingText: 'Loading...',
10884     /**
10885      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
10886      */
10887     resizable: false,
10888     /**
10889      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
10890      */
10891     handleHeight : 8,
10892     /**
10893      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
10894      * traditional select (defaults to true)
10895      */
10896     editable: true,
10897     /**
10898      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
10899      */
10900     allQuery: '',
10901     /**
10902      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
10903      */
10904     mode: 'remote',
10905     /**
10906      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
10907      * listWidth has a higher value)
10908      */
10909     minListWidth : 70,
10910     /**
10911      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
10912      * allow the user to set arbitrary text into the field (defaults to false)
10913      */
10914     forceSelection:false,
10915     /**
10916      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
10917      * if typeAhead = true (defaults to 250)
10918      */
10919     typeAheadDelay : 250,
10920     /**
10921      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
10922      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
10923      */
10924     valueNotFoundText : undefined,
10925     /**
10926      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
10927      */
10928     blockFocus : false,
10929     
10930     /**
10931      * @cfg {Boolean} disableClear Disable showing of clear button.
10932      */
10933     disableClear : false,
10934     /**
10935      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
10936      */
10937     alwaysQuery : false,
10938     
10939     /**
10940      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
10941      */
10942     multiple : false,
10943     
10944     /**
10945      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
10946      */
10947     invalidClass : "has-warning",
10948     
10949     /**
10950      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
10951      */
10952     validClass : "has-success",
10953     
10954     //private
10955     addicon : false,
10956     editicon: false,
10957     
10958     page: 0,
10959     hasQuery: false,
10960     append: false,
10961     loadNext: false,
10962     autoFocus : true,
10963     tickable : false,
10964     btnPosition : 'right',
10965     triggerList : true,
10966     showToggleBtn : true,
10967     // element that contains real text value.. (when hidden is used..)
10968     
10969     getAutoCreate : function()
10970     {
10971         var cfg = false;
10972         
10973         /*
10974          *  Normal ComboBox
10975          */
10976         if(!this.tickable){
10977             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
10978             return cfg;
10979         }
10980         
10981         /*
10982          *  ComboBox with tickable selections
10983          */
10984              
10985         var align = this.labelAlign || this.parentLabelAlign();
10986         
10987         cfg = {
10988             cls : 'form-group roo-combobox-tickable' //input-group
10989         };
10990         
10991         var buttons = {
10992             tag : 'div',
10993             cls : 'tickable-buttons',
10994             cn : [
10995                 {
10996                     tag : 'button',
10997                     type : 'button',
10998                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
10999                     html : 'Edit'
11000                 },
11001                 {
11002                     tag : 'button',
11003                     type : 'button',
11004                     name : 'ok',
11005                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11006                     html : 'Done'
11007                 },
11008                 {
11009                     tag : 'button',
11010                     type : 'button',
11011                     name : 'cancel',
11012                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11013                     html : 'Cancel'
11014                 }
11015             ]
11016         };
11017         
11018         if(this.editable){
11019             buttons.cn.unshift({
11020                 tag: 'input',
11021                 cls: 'select2-search-field-input'
11022             });
11023         }
11024         
11025         var _this = this;
11026         
11027         Roo.each(buttons.cn, function(c){
11028             if (_this.size) {
11029                 c.cls += ' btn-' + _this.size;
11030             }
11031
11032             if (_this.disabled) {
11033                 c.disabled = true;
11034             }
11035         });
11036         
11037         var box = {
11038             tag: 'div',
11039             cn: [
11040                 {
11041                     tag: 'input',
11042                     type : 'hidden',
11043                     cls: 'form-hidden-field'
11044                 },
11045                 {
11046                     tag: 'ul',
11047                     cls: 'select2-choices',
11048                     cn:[
11049                         {
11050                             tag: 'li',
11051                             cls: 'select2-search-field',
11052                             cn: [
11053
11054                                 buttons
11055                             ]
11056                         }
11057                     ]
11058                 }
11059             ]
11060         }
11061         
11062         var combobox = {
11063             cls: 'select2-container input-group select2-container-multi',
11064             cn: [
11065                 box
11066 //                {
11067 //                    tag: 'ul',
11068 //                    cls: 'typeahead typeahead-long dropdown-menu',
11069 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
11070 //                }
11071             ]
11072         };
11073         
11074         if(this.hasFeedback && !this.allowBlank){
11075             
11076             var feedback = {
11077                 tag: 'span',
11078                 cls: 'glyphicon form-control-feedback'
11079             };
11080
11081             combobox.cn.push(feedback);
11082         }
11083         
11084         if (align ==='left' && this.fieldLabel.length) {
11085             
11086                 Roo.log("left and has label");
11087                 cfg.cn = [
11088                     
11089                     {
11090                         tag: 'label',
11091                         'for' :  id,
11092                         cls : 'control-label col-sm-' + this.labelWidth,
11093                         html : this.fieldLabel
11094                         
11095                     },
11096                     {
11097                         cls : "col-sm-" + (12 - this.labelWidth), 
11098                         cn: [
11099                             combobox
11100                         ]
11101                     }
11102                     
11103                 ];
11104         } else if ( this.fieldLabel.length) {
11105                 Roo.log(" label");
11106                  cfg.cn = [
11107                    
11108                     {
11109                         tag: 'label',
11110                         //cls : 'input-group-addon',
11111                         html : this.fieldLabel
11112                         
11113                     },
11114                     
11115                     combobox
11116                     
11117                 ];
11118
11119         } else {
11120             
11121                 Roo.log(" no label && no align");
11122                 cfg = combobox
11123                      
11124                 
11125         }
11126          
11127         var settings=this;
11128         ['xs','sm','md','lg'].map(function(size){
11129             if (settings[size]) {
11130                 cfg.cls += ' col-' + size + '-' + settings[size];
11131             }
11132         });
11133         
11134         return cfg;
11135         
11136     },
11137     
11138     // private
11139     initEvents: function()
11140     {
11141         
11142         if (!this.store) {
11143             throw "can not find store for combo";
11144         }
11145         this.store = Roo.factory(this.store, Roo.data);
11146         
11147         if(this.tickable){
11148             this.initTickableEvents();
11149             return;
11150         }
11151         
11152         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11153         
11154         if(this.hiddenName){
11155             
11156             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11157             
11158             this.hiddenField.dom.value =
11159                 this.hiddenValue !== undefined ? this.hiddenValue :
11160                 this.value !== undefined ? this.value : '';
11161
11162             // prevent input submission
11163             this.el.dom.removeAttribute('name');
11164             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11165              
11166              
11167         }
11168         //if(Roo.isGecko){
11169         //    this.el.dom.setAttribute('autocomplete', 'off');
11170         //}
11171         
11172         var cls = 'x-combo-list';
11173         
11174         //this.list = new Roo.Layer({
11175         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11176         //});
11177         
11178         var _this = this;
11179         
11180         (function(){
11181             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11182             _this.list.setWidth(lw);
11183         }).defer(100);
11184         
11185         this.list.on('mouseover', this.onViewOver, this);
11186         this.list.on('mousemove', this.onViewMove, this);
11187         
11188         this.list.on('scroll', this.onViewScroll, this);
11189         
11190         /*
11191         this.list.swallowEvent('mousewheel');
11192         this.assetHeight = 0;
11193
11194         if(this.title){
11195             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11196             this.assetHeight += this.header.getHeight();
11197         }
11198
11199         this.innerList = this.list.createChild({cls:cls+'-inner'});
11200         this.innerList.on('mouseover', this.onViewOver, this);
11201         this.innerList.on('mousemove', this.onViewMove, this);
11202         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11203         
11204         if(this.allowBlank && !this.pageSize && !this.disableClear){
11205             this.footer = this.list.createChild({cls:cls+'-ft'});
11206             this.pageTb = new Roo.Toolbar(this.footer);
11207            
11208         }
11209         if(this.pageSize){
11210             this.footer = this.list.createChild({cls:cls+'-ft'});
11211             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11212                     {pageSize: this.pageSize});
11213             
11214         }
11215         
11216         if (this.pageTb && this.allowBlank && !this.disableClear) {
11217             var _this = this;
11218             this.pageTb.add(new Roo.Toolbar.Fill(), {
11219                 cls: 'x-btn-icon x-btn-clear',
11220                 text: '&#160;',
11221                 handler: function()
11222                 {
11223                     _this.collapse();
11224                     _this.clearValue();
11225                     _this.onSelect(false, -1);
11226                 }
11227             });
11228         }
11229         if (this.footer) {
11230             this.assetHeight += this.footer.getHeight();
11231         }
11232         */
11233             
11234         if(!this.tpl){
11235             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11236         }
11237
11238         this.view = new Roo.View(this.list, this.tpl, {
11239             singleSelect:true, store: this.store, selectedClass: this.selectedClass
11240         });
11241         //this.view.wrapEl.setDisplayed(false);
11242         this.view.on('click', this.onViewClick, this);
11243         
11244         
11245         
11246         this.store.on('beforeload', this.onBeforeLoad, this);
11247         this.store.on('load', this.onLoad, this);
11248         this.store.on('loadexception', this.onLoadException, this);
11249         /*
11250         if(this.resizable){
11251             this.resizer = new Roo.Resizable(this.list,  {
11252                pinned:true, handles:'se'
11253             });
11254             this.resizer.on('resize', function(r, w, h){
11255                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11256                 this.listWidth = w;
11257                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11258                 this.restrictHeight();
11259             }, this);
11260             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11261         }
11262         */
11263         if(!this.editable){
11264             this.editable = true;
11265             this.setEditable(false);
11266         }
11267         
11268         /*
11269         
11270         if (typeof(this.events.add.listeners) != 'undefined') {
11271             
11272             this.addicon = this.wrap.createChild(
11273                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
11274        
11275             this.addicon.on('click', function(e) {
11276                 this.fireEvent('add', this);
11277             }, this);
11278         }
11279         if (typeof(this.events.edit.listeners) != 'undefined') {
11280             
11281             this.editicon = this.wrap.createChild(
11282                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
11283             if (this.addicon) {
11284                 this.editicon.setStyle('margin-left', '40px');
11285             }
11286             this.editicon.on('click', function(e) {
11287                 
11288                 // we fire even  if inothing is selected..
11289                 this.fireEvent('edit', this, this.lastData );
11290                 
11291             }, this);
11292         }
11293         */
11294         
11295         this.keyNav = new Roo.KeyNav(this.inputEl(), {
11296             "up" : function(e){
11297                 this.inKeyMode = true;
11298                 this.selectPrev();
11299             },
11300
11301             "down" : function(e){
11302                 if(!this.isExpanded()){
11303                     this.onTriggerClick();
11304                 }else{
11305                     this.inKeyMode = true;
11306                     this.selectNext();
11307                 }
11308             },
11309
11310             "enter" : function(e){
11311 //                this.onViewClick();
11312                 //return true;
11313                 this.collapse();
11314                 
11315                 if(this.fireEvent("specialkey", this, e)){
11316                     this.onViewClick(false);
11317                 }
11318                 
11319                 return true;
11320             },
11321
11322             "esc" : function(e){
11323                 this.collapse();
11324             },
11325
11326             "tab" : function(e){
11327                 this.collapse();
11328                 
11329                 if(this.fireEvent("specialkey", this, e)){
11330                     this.onViewClick(false);
11331                 }
11332                 
11333                 return true;
11334             },
11335
11336             scope : this,
11337
11338             doRelay : function(foo, bar, hname){
11339                 if(hname == 'down' || this.scope.isExpanded()){
11340                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11341                 }
11342                 return true;
11343             },
11344
11345             forceKeyDown: true
11346         });
11347         
11348         
11349         this.queryDelay = Math.max(this.queryDelay || 10,
11350                 this.mode == 'local' ? 10 : 250);
11351         
11352         
11353         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11354         
11355         if(this.typeAhead){
11356             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11357         }
11358         if(this.editable !== false){
11359             this.inputEl().on("keyup", this.onKeyUp, this);
11360         }
11361         if(this.forceSelection){
11362             this.inputEl().on('blur', this.doForce, this);
11363         }
11364         
11365         if(this.multiple){
11366             this.choices = this.el.select('ul.select2-choices', true).first();
11367             this.searchField = this.el.select('ul li.select2-search-field', true).first();
11368         }
11369     },
11370     
11371     initTickableEvents: function()
11372     {   
11373         this.createList();
11374         
11375         if(this.hiddenName){
11376             
11377             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11378             
11379             this.hiddenField.dom.value =
11380                 this.hiddenValue !== undefined ? this.hiddenValue :
11381                 this.value !== undefined ? this.value : '';
11382
11383             // prevent input submission
11384             this.el.dom.removeAttribute('name');
11385             this.hiddenField.dom.setAttribute('name', this.hiddenName);
11386              
11387              
11388         }
11389         
11390 //        this.list = this.el.select('ul.dropdown-menu',true).first();
11391         
11392         this.choices = this.el.select('ul.select2-choices', true).first();
11393         this.searchField = this.el.select('ul li.select2-search-field', true).first();
11394         if(this.triggerList){
11395             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11396         }
11397          
11398         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11399         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11400         
11401         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11402         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11403         
11404         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11405         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11406         
11407         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11408         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11409         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11410         
11411         this.okBtn.hide();
11412         this.cancelBtn.hide();
11413         
11414         var _this = this;
11415         
11416         (function(){
11417             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11418             _this.list.setWidth(lw);
11419         }).defer(100);
11420         
11421         this.list.on('mouseover', this.onViewOver, this);
11422         this.list.on('mousemove', this.onViewMove, this);
11423         
11424         this.list.on('scroll', this.onViewScroll, this);
11425         
11426         if(!this.tpl){
11427             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>';
11428         }
11429
11430         this.view = new Roo.View(this.list, this.tpl, {
11431             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11432         });
11433         
11434         //this.view.wrapEl.setDisplayed(false);
11435         this.view.on('click', this.onViewClick, this);
11436         
11437         
11438         
11439         this.store.on('beforeload', this.onBeforeLoad, this);
11440         this.store.on('load', this.onLoad, this);
11441         this.store.on('loadexception', this.onLoadException, this);
11442         
11443         if(this.editable){
11444             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11445                 "up" : function(e){
11446                     this.inKeyMode = true;
11447                     this.selectPrev();
11448                 },
11449
11450                 "down" : function(e){
11451                     this.inKeyMode = true;
11452                     this.selectNext();
11453                 },
11454
11455                 "enter" : function(e){
11456                     if(this.fireEvent("specialkey", this, e)){
11457                         this.onViewClick(false);
11458                     }
11459                     
11460                     return true;
11461                 },
11462
11463                 "esc" : function(e){
11464                     this.onTickableFooterButtonClick(e, false, false);
11465                 },
11466
11467                 "tab" : function(e){
11468                     this.fireEvent("specialkey", this, e);
11469                     
11470                     this.onTickableFooterButtonClick(e, false, false);
11471                     
11472                     return true;
11473                 },
11474
11475                 scope : this,
11476
11477                 doRelay : function(e, fn, key){
11478                     if(this.scope.isExpanded()){
11479                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11480                     }
11481                     return true;
11482                 },
11483
11484                 forceKeyDown: true
11485             });
11486         }
11487         
11488         this.queryDelay = Math.max(this.queryDelay || 10,
11489                 this.mode == 'local' ? 10 : 250);
11490         
11491         
11492         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11493         
11494         if(this.typeAhead){
11495             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11496         }
11497         
11498         if(this.editable !== false){
11499             this.tickableInputEl().on("keyup", this.onKeyUp, this);
11500         }
11501         
11502     },
11503
11504     onDestroy : function(){
11505         if(this.view){
11506             this.view.setStore(null);
11507             this.view.el.removeAllListeners();
11508             this.view.el.remove();
11509             this.view.purgeListeners();
11510         }
11511         if(this.list){
11512             this.list.dom.innerHTML  = '';
11513         }
11514         
11515         if(this.store){
11516             this.store.un('beforeload', this.onBeforeLoad, this);
11517             this.store.un('load', this.onLoad, this);
11518             this.store.un('loadexception', this.onLoadException, this);
11519         }
11520         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11521     },
11522
11523     // private
11524     fireKey : function(e){
11525         if(e.isNavKeyPress() && !this.list.isVisible()){
11526             this.fireEvent("specialkey", this, e);
11527         }
11528     },
11529
11530     // private
11531     onResize: function(w, h){
11532 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11533 //        
11534 //        if(typeof w != 'number'){
11535 //            // we do not handle it!?!?
11536 //            return;
11537 //        }
11538 //        var tw = this.trigger.getWidth();
11539 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
11540 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
11541 //        var x = w - tw;
11542 //        this.inputEl().setWidth( this.adjustWidth('input', x));
11543 //            
11544 //        //this.trigger.setStyle('left', x+'px');
11545 //        
11546 //        if(this.list && this.listWidth === undefined){
11547 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11548 //            this.list.setWidth(lw);
11549 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11550 //        }
11551         
11552     
11553         
11554     },
11555
11556     /**
11557      * Allow or prevent the user from directly editing the field text.  If false is passed,
11558      * the user will only be able to select from the items defined in the dropdown list.  This method
11559      * is the runtime equivalent of setting the 'editable' config option at config time.
11560      * @param {Boolean} value True to allow the user to directly edit the field text
11561      */
11562     setEditable : function(value){
11563         if(value == this.editable){
11564             return;
11565         }
11566         this.editable = value;
11567         if(!value){
11568             this.inputEl().dom.setAttribute('readOnly', true);
11569             this.inputEl().on('mousedown', this.onTriggerClick,  this);
11570             this.inputEl().addClass('x-combo-noedit');
11571         }else{
11572             this.inputEl().dom.setAttribute('readOnly', false);
11573             this.inputEl().un('mousedown', this.onTriggerClick,  this);
11574             this.inputEl().removeClass('x-combo-noedit');
11575         }
11576     },
11577
11578     // private
11579     
11580     onBeforeLoad : function(combo,opts){
11581         if(!this.hasFocus){
11582             return;
11583         }
11584          if (!opts.add) {
11585             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11586          }
11587         this.restrictHeight();
11588         this.selectedIndex = -1;
11589     },
11590
11591     // private
11592     onLoad : function(){
11593         
11594         this.hasQuery = false;
11595         
11596         if(!this.hasFocus){
11597             return;
11598         }
11599         
11600         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11601             this.loading.hide();
11602         }
11603              
11604         if(this.store.getCount() > 0){
11605             this.expand();
11606             this.restrictHeight();
11607             if(this.lastQuery == this.allQuery){
11608                 if(this.editable && !this.tickable){
11609                     this.inputEl().dom.select();
11610                 }
11611                 
11612                 if(
11613                     !this.selectByValue(this.value, true) &&
11614                     this.autoFocus && 
11615                     (
11616                         !this.store.lastOptions ||
11617                         typeof(this.store.lastOptions.add) == 'undefined' || 
11618                         this.store.lastOptions.add != true
11619                     )
11620                 ){
11621                     this.select(0, true);
11622                 }
11623             }else{
11624                 if(this.autoFocus){
11625                     this.selectNext();
11626                 }
11627                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11628                     this.taTask.delay(this.typeAheadDelay);
11629                 }
11630             }
11631         }else{
11632             this.onEmptyResults();
11633         }
11634         
11635         //this.el.focus();
11636     },
11637     // private
11638     onLoadException : function()
11639     {
11640         this.hasQuery = false;
11641         
11642         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11643             this.loading.hide();
11644         }
11645         
11646         if(this.tickable && this.editable){
11647             return;
11648         }
11649         
11650         this.collapse();
11651         
11652         Roo.log(this.store.reader.jsonData);
11653         if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11654             // fixme
11655             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11656         }
11657         
11658         
11659     },
11660     // private
11661     onTypeAhead : function(){
11662         if(this.store.getCount() > 0){
11663             var r = this.store.getAt(0);
11664             var newValue = r.data[this.displayField];
11665             var len = newValue.length;
11666             var selStart = this.getRawValue().length;
11667             
11668             if(selStart != len){
11669                 this.setRawValue(newValue);
11670                 this.selectText(selStart, newValue.length);
11671             }
11672         }
11673     },
11674
11675     // private
11676     onSelect : function(record, index){
11677         
11678         if(this.fireEvent('beforeselect', this, record, index) !== false){
11679         
11680             this.setFromData(index > -1 ? record.data : false);
11681             
11682             this.collapse();
11683             this.fireEvent('select', this, record, index);
11684         }
11685     },
11686
11687     /**
11688      * Returns the currently selected field value or empty string if no value is set.
11689      * @return {String} value The selected value
11690      */
11691     getValue : function(){
11692         
11693         if(this.multiple){
11694             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11695         }
11696         
11697         if(this.valueField){
11698             return typeof this.value != 'undefined' ? this.value : '';
11699         }else{
11700             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11701         }
11702     },
11703
11704     /**
11705      * Clears any text/value currently set in the field
11706      */
11707     clearValue : function(){
11708         if(this.hiddenField){
11709             this.hiddenField.dom.value = '';
11710         }
11711         this.value = '';
11712         this.setRawValue('');
11713         this.lastSelectionText = '';
11714         this.lastData = false;
11715         
11716     },
11717
11718     /**
11719      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
11720      * will be displayed in the field.  If the value does not match the data value of an existing item,
11721      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11722      * Otherwise the field will be blank (although the value will still be set).
11723      * @param {String} value The value to match
11724      */
11725     setValue : function(v){
11726         if(this.multiple){
11727             this.syncValue();
11728             return;
11729         }
11730         
11731         var text = v;
11732         if(this.valueField){
11733             var r = this.findRecord(this.valueField, v);
11734             if(r){
11735                 text = r.data[this.displayField];
11736             }else if(this.valueNotFoundText !== undefined){
11737                 text = this.valueNotFoundText;
11738             }
11739         }
11740         this.lastSelectionText = text;
11741         if(this.hiddenField){
11742             this.hiddenField.dom.value = v;
11743         }
11744         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11745         this.value = v;
11746     },
11747     /**
11748      * @property {Object} the last set data for the element
11749      */
11750     
11751     lastData : false,
11752     /**
11753      * Sets the value of the field based on a object which is related to the record format for the store.
11754      * @param {Object} value the value to set as. or false on reset?
11755      */
11756     setFromData : function(o){
11757         
11758         if(this.multiple){
11759             this.addItem(o);
11760             return;
11761         }
11762             
11763         var dv = ''; // display value
11764         var vv = ''; // value value..
11765         this.lastData = o;
11766         if (this.displayField) {
11767             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11768         } else {
11769             // this is an error condition!!!
11770             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
11771         }
11772         
11773         if(this.valueField){
11774             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11775         }
11776         
11777         if(this.hiddenField){
11778             this.hiddenField.dom.value = vv;
11779             
11780             this.lastSelectionText = dv;
11781             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11782             this.value = vv;
11783             return;
11784         }
11785         // no hidden field.. - we store the value in 'value', but still display
11786         // display field!!!!
11787         this.lastSelectionText = dv;
11788         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11789         this.value = vv;
11790         
11791         
11792     },
11793     // private
11794     reset : function(){
11795         // overridden so that last data is reset..
11796         
11797         if(this.multiple){
11798             this.clearItem();
11799             return;
11800         }
11801         
11802         this.setValue(this.originalValue);
11803         this.clearInvalid();
11804         this.lastData = false;
11805         if (this.view) {
11806             this.view.clearSelections();
11807         }
11808     },
11809     // private
11810     findRecord : function(prop, value){
11811         var record;
11812         if(this.store.getCount() > 0){
11813             this.store.each(function(r){
11814                 if(r.data[prop] == value){
11815                     record = r;
11816                     return false;
11817                 }
11818                 return true;
11819             });
11820         }
11821         return record;
11822     },
11823     
11824     getName: function()
11825     {
11826         // returns hidden if it's set..
11827         if (!this.rendered) {return ''};
11828         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
11829         
11830     },
11831     // private
11832     onViewMove : function(e, t){
11833         this.inKeyMode = false;
11834     },
11835
11836     // private
11837     onViewOver : function(e, t){
11838         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
11839             return;
11840         }
11841         var item = this.view.findItemFromChild(t);
11842         
11843         if(item){
11844             var index = this.view.indexOf(item);
11845             this.select(index, false);
11846         }
11847     },
11848
11849     // private
11850     onViewClick : function(view, doFocus, el, e)
11851     {
11852         var index = this.view.getSelectedIndexes()[0];
11853         
11854         var r = this.store.getAt(index);
11855         
11856         if(this.tickable){
11857             
11858             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
11859                 return;
11860             }
11861             
11862             var rm = false;
11863             var _this = this;
11864             
11865             Roo.each(this.tickItems, function(v,k){
11866                 
11867                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
11868                     _this.tickItems.splice(k, 1);
11869                     
11870                     if(typeof(e) == 'undefined' && view == false){
11871                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
11872                     }
11873                     
11874                     rm = true;
11875                     return;
11876                 }
11877             });
11878             
11879             if(rm){
11880                 return;
11881             }
11882             
11883             this.tickItems.push(r.data);
11884             
11885             if(typeof(e) == 'undefined' && view == false){
11886                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
11887             }
11888                     
11889             return;
11890         }
11891         
11892         if(r){
11893             this.onSelect(r, index);
11894         }
11895         if(doFocus !== false && !this.blockFocus){
11896             this.inputEl().focus();
11897         }
11898     },
11899
11900     // private
11901     restrictHeight : function(){
11902         //this.innerList.dom.style.height = '';
11903         //var inner = this.innerList.dom;
11904         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
11905         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
11906         //this.list.beginUpdate();
11907         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
11908         this.list.alignTo(this.inputEl(), this.listAlign);
11909         this.list.alignTo(this.inputEl(), this.listAlign);
11910         //this.list.endUpdate();
11911     },
11912
11913     // private
11914     onEmptyResults : function(){
11915         
11916         if(this.tickable && this.editable){
11917             this.restrictHeight();
11918             return;
11919         }
11920         
11921         this.collapse();
11922     },
11923
11924     /**
11925      * Returns true if the dropdown list is expanded, else false.
11926      */
11927     isExpanded : function(){
11928         return this.list.isVisible();
11929     },
11930
11931     /**
11932      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
11933      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11934      * @param {String} value The data value of the item to select
11935      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11936      * selected item if it is not currently in view (defaults to true)
11937      * @return {Boolean} True if the value matched an item in the list, else false
11938      */
11939     selectByValue : function(v, scrollIntoView){
11940         if(v !== undefined && v !== null){
11941             var r = this.findRecord(this.valueField || this.displayField, v);
11942             if(r){
11943                 this.select(this.store.indexOf(r), scrollIntoView);
11944                 return true;
11945             }
11946         }
11947         return false;
11948     },
11949
11950     /**
11951      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
11952      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
11953      * @param {Number} index The zero-based index of the list item to select
11954      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
11955      * selected item if it is not currently in view (defaults to true)
11956      */
11957     select : function(index, scrollIntoView){
11958         this.selectedIndex = index;
11959         this.view.select(index);
11960         if(scrollIntoView !== false){
11961             var el = this.view.getNode(index);
11962             /*
11963              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
11964              */
11965             if(el){
11966                 this.list.scrollChildIntoView(el, false);
11967             }
11968         }
11969     },
11970
11971     // private
11972     selectNext : function(){
11973         var ct = this.store.getCount();
11974         if(ct > 0){
11975             if(this.selectedIndex == -1){
11976                 this.select(0);
11977             }else if(this.selectedIndex < ct-1){
11978                 this.select(this.selectedIndex+1);
11979             }
11980         }
11981     },
11982
11983     // private
11984     selectPrev : function(){
11985         var ct = this.store.getCount();
11986         if(ct > 0){
11987             if(this.selectedIndex == -1){
11988                 this.select(0);
11989             }else if(this.selectedIndex != 0){
11990                 this.select(this.selectedIndex-1);
11991             }
11992         }
11993     },
11994
11995     // private
11996     onKeyUp : function(e){
11997         if(this.editable !== false && !e.isSpecialKey()){
11998             this.lastKey = e.getKey();
11999             this.dqTask.delay(this.queryDelay);
12000         }
12001     },
12002
12003     // private
12004     validateBlur : function(){
12005         return !this.list || !this.list.isVisible();   
12006     },
12007
12008     // private
12009     initQuery : function(){
12010         
12011         var v = this.getRawValue();
12012         
12013         if(this.tickable && this.editable){
12014             v = this.tickableInputEl().getValue();
12015         }
12016         
12017         this.doQuery(v);
12018     },
12019
12020     // private
12021     doForce : function(){
12022         if(this.inputEl().dom.value.length > 0){
12023             this.inputEl().dom.value =
12024                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12025              
12026         }
12027     },
12028
12029     /**
12030      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
12031      * query allowing the query action to be canceled if needed.
12032      * @param {String} query The SQL query to execute
12033      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12034      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
12035      * saved in the current store (defaults to false)
12036      */
12037     doQuery : function(q, forceAll){
12038         
12039         if(q === undefined || q === null){
12040             q = '';
12041         }
12042         var qe = {
12043             query: q,
12044             forceAll: forceAll,
12045             combo: this,
12046             cancel:false
12047         };
12048         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12049             return false;
12050         }
12051         q = qe.query;
12052         
12053         forceAll = qe.forceAll;
12054         if(forceAll === true || (q.length >= this.minChars)){
12055             
12056             this.hasQuery = true;
12057             
12058             if(this.lastQuery != q || this.alwaysQuery){
12059                 this.lastQuery = q;
12060                 if(this.mode == 'local'){
12061                     this.selectedIndex = -1;
12062                     if(forceAll){
12063                         this.store.clearFilter();
12064                     }else{
12065                         this.store.filter(this.displayField, q);
12066                     }
12067                     this.onLoad();
12068                 }else{
12069                     
12070                     this.store.baseParams[this.queryParam] = q;
12071                     
12072                     var options = {params : this.getParams(q)};
12073                     
12074                     if(this.loadNext){
12075                         options.add = true;
12076                         options.params.start = this.page * this.pageSize;
12077                     }
12078                     
12079                     this.store.load(options);
12080                     
12081                     /*
12082                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
12083                      *  we should expand the list on onLoad
12084                      *  so command out it
12085                      */
12086 //                    this.expand();
12087                 }
12088             }else{
12089                 this.selectedIndex = -1;
12090                 this.onLoad();   
12091             }
12092         }
12093         
12094         this.loadNext = false;
12095     },
12096
12097     // private
12098     getParams : function(q){
12099         var p = {};
12100         //p[this.queryParam] = q;
12101         
12102         if(this.pageSize){
12103             p.start = 0;
12104             p.limit = this.pageSize;
12105         }
12106         return p;
12107     },
12108
12109     /**
12110      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12111      */
12112     collapse : function(){
12113         if(!this.isExpanded()){
12114             return;
12115         }
12116         
12117         this.list.hide();
12118         
12119         if(this.tickable){
12120             this.hasFocus = false;
12121             this.okBtn.hide();
12122             this.cancelBtn.hide();
12123             this.trigger.show();
12124             
12125             if(this.editable){
12126                 this.tickableInputEl().dom.value = '';
12127                 this.tickableInputEl().blur();
12128             }
12129             
12130         }
12131         
12132         Roo.get(document).un('mousedown', this.collapseIf, this);
12133         Roo.get(document).un('mousewheel', this.collapseIf, this);
12134         if (!this.editable) {
12135             Roo.get(document).un('keydown', this.listKeyPress, this);
12136         }
12137         this.fireEvent('collapse', this);
12138     },
12139
12140     // private
12141     collapseIf : function(e){
12142         var in_combo  = e.within(this.el);
12143         var in_list =  e.within(this.list);
12144         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12145         
12146         if (in_combo || in_list || is_list) {
12147             //e.stopPropagation();
12148             return;
12149         }
12150         
12151         if(this.tickable){
12152             this.onTickableFooterButtonClick(e, false, false);
12153         }
12154
12155         this.collapse();
12156         
12157     },
12158
12159     /**
12160      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12161      */
12162     expand : function(){
12163        
12164         if(this.isExpanded() || !this.hasFocus){
12165             return;
12166         }
12167         
12168         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12169         this.list.setWidth(lw);
12170         
12171         
12172          Roo.log('expand');
12173         
12174         this.list.show();
12175         
12176         this.restrictHeight();
12177         
12178         if(this.tickable){
12179             
12180             this.tickItems = Roo.apply([], this.item);
12181             
12182             this.okBtn.show();
12183             this.cancelBtn.show();
12184             this.trigger.hide();
12185             
12186             if(this.editable){
12187                 this.tickableInputEl().focus();
12188             }
12189             
12190         }
12191         
12192         Roo.get(document).on('mousedown', this.collapseIf, this);
12193         Roo.get(document).on('mousewheel', this.collapseIf, this);
12194         if (!this.editable) {
12195             Roo.get(document).on('keydown', this.listKeyPress, this);
12196         }
12197         
12198         this.fireEvent('expand', this);
12199     },
12200
12201     // private
12202     // Implements the default empty TriggerField.onTriggerClick function
12203     onTriggerClick : function(e)
12204     {
12205         Roo.log('trigger click');
12206         
12207         if(this.disabled || !this.triggerList){
12208             return;
12209         }
12210         
12211         this.page = 0;
12212         this.loadNext = false;
12213         
12214         if(this.isExpanded()){
12215             this.collapse();
12216             if (!this.blockFocus) {
12217                 this.inputEl().focus();
12218             }
12219             
12220         }else {
12221             this.hasFocus = true;
12222             if(this.triggerAction == 'all') {
12223                 this.doQuery(this.allQuery, true);
12224             } else {
12225                 this.doQuery(this.getRawValue());
12226             }
12227             if (!this.blockFocus) {
12228                 this.inputEl().focus();
12229             }
12230         }
12231     },
12232     
12233     onTickableTriggerClick : function(e)
12234     {
12235         if(this.disabled){
12236             return;
12237         }
12238         
12239         this.page = 0;
12240         this.loadNext = false;
12241         this.hasFocus = true;
12242         
12243         if(this.triggerAction == 'all') {
12244             this.doQuery(this.allQuery, true);
12245         } else {
12246             this.doQuery(this.getRawValue());
12247         }
12248     },
12249     
12250     onSearchFieldClick : function(e)
12251     {
12252         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12253             this.onTickableFooterButtonClick(e, false, false);
12254             return;
12255         }
12256         
12257         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12258             return;
12259         }
12260         
12261         this.page = 0;
12262         this.loadNext = false;
12263         this.hasFocus = true;
12264         
12265         if(this.triggerAction == 'all') {
12266             this.doQuery(this.allQuery, true);
12267         } else {
12268             this.doQuery(this.getRawValue());
12269         }
12270     },
12271     
12272     listKeyPress : function(e)
12273     {
12274         //Roo.log('listkeypress');
12275         // scroll to first matching element based on key pres..
12276         if (e.isSpecialKey()) {
12277             return false;
12278         }
12279         var k = String.fromCharCode(e.getKey()).toUpperCase();
12280         //Roo.log(k);
12281         var match  = false;
12282         var csel = this.view.getSelectedNodes();
12283         var cselitem = false;
12284         if (csel.length) {
12285             var ix = this.view.indexOf(csel[0]);
12286             cselitem  = this.store.getAt(ix);
12287             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12288                 cselitem = false;
12289             }
12290             
12291         }
12292         
12293         this.store.each(function(v) { 
12294             if (cselitem) {
12295                 // start at existing selection.
12296                 if (cselitem.id == v.id) {
12297                     cselitem = false;
12298                 }
12299                 return true;
12300             }
12301                 
12302             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12303                 match = this.store.indexOf(v);
12304                 return false;
12305             }
12306             return true;
12307         }, this);
12308         
12309         if (match === false) {
12310             return true; // no more action?
12311         }
12312         // scroll to?
12313         this.view.select(match);
12314         var sn = Roo.get(this.view.getSelectedNodes()[0])
12315         sn.scrollIntoView(sn.dom.parentNode, false);
12316     },
12317     
12318     onViewScroll : function(e, t){
12319         
12320         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){
12321             return;
12322         }
12323         
12324         this.hasQuery = true;
12325         
12326         this.loading = this.list.select('.loading', true).first();
12327         
12328         if(this.loading === null){
12329             this.list.createChild({
12330                 tag: 'div',
12331                 cls: 'loading select2-more-results select2-active',
12332                 html: 'Loading more results...'
12333             })
12334             
12335             this.loading = this.list.select('.loading', true).first();
12336             
12337             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12338             
12339             this.loading.hide();
12340         }
12341         
12342         this.loading.show();
12343         
12344         var _combo = this;
12345         
12346         this.page++;
12347         this.loadNext = true;
12348         
12349         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12350         
12351         return;
12352     },
12353     
12354     addItem : function(o)
12355     {   
12356         var dv = ''; // display value
12357         
12358         if (this.displayField) {
12359             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12360         } else {
12361             // this is an error condition!!!
12362             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
12363         }
12364         
12365         if(!dv.length){
12366             return;
12367         }
12368         
12369         var choice = this.choices.createChild({
12370             tag: 'li',
12371             cls: 'select2-search-choice',
12372             cn: [
12373                 {
12374                     tag: 'div',
12375                     html: dv
12376                 },
12377                 {
12378                     tag: 'a',
12379                     href: '#',
12380                     cls: 'select2-search-choice-close',
12381                     tabindex: '-1'
12382                 }
12383             ]
12384             
12385         }, this.searchField);
12386         
12387         var close = choice.select('a.select2-search-choice-close', true).first()
12388         
12389         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12390         
12391         this.item.push(o);
12392         
12393         this.lastData = o;
12394         
12395         this.syncValue();
12396         
12397         this.inputEl().dom.value = '';
12398         
12399         this.validate();
12400     },
12401     
12402     onRemoveItem : function(e, _self, o)
12403     {
12404         e.preventDefault();
12405         
12406         this.lastItem = Roo.apply([], this.item);
12407         
12408         var index = this.item.indexOf(o.data) * 1;
12409         
12410         if( index < 0){
12411             Roo.log('not this item?!');
12412             return;
12413         }
12414         
12415         this.item.splice(index, 1);
12416         o.item.remove();
12417         
12418         this.syncValue();
12419         
12420         this.fireEvent('remove', this, e);
12421         
12422         this.validate();
12423         
12424     },
12425     
12426     syncValue : function()
12427     {
12428         if(!this.item.length){
12429             this.clearValue();
12430             return;
12431         }
12432             
12433         var value = [];
12434         var _this = this;
12435         Roo.each(this.item, function(i){
12436             if(_this.valueField){
12437                 value.push(i[_this.valueField]);
12438                 return;
12439             }
12440
12441             value.push(i);
12442         });
12443
12444         this.value = value.join(',');
12445
12446         if(this.hiddenField){
12447             this.hiddenField.dom.value = this.value;
12448         }
12449     },
12450     
12451     clearItem : function()
12452     {
12453         if(!this.multiple){
12454             return;
12455         }
12456         
12457         this.item = [];
12458         
12459         Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12460            c.remove();
12461         });
12462         
12463         this.syncValue();
12464         
12465         this.validate();
12466     },
12467     
12468     inputEl: function ()
12469     {
12470         if(this.tickable){
12471             return this.searchField;
12472         }
12473         return this.el.select('input.form-control',true).first();
12474     },
12475     
12476     
12477     onTickableFooterButtonClick : function(e, btn, el)
12478     {
12479         e.preventDefault();
12480         
12481         this.lastItem = Roo.apply([], this.item);
12482         
12483         if(btn && btn.name == 'cancel'){
12484             this.tickItems = Roo.apply([], this.item);
12485             this.collapse();
12486             return;
12487         }
12488         
12489         this.clearItem();
12490         
12491         var _this = this;
12492         
12493         Roo.each(this.tickItems, function(o){
12494             _this.addItem(o);
12495         });
12496         
12497         this.collapse();
12498         
12499     },
12500     
12501     validate : function()
12502     {
12503         var v = this.getRawValue();
12504         
12505         if(this.multiple){
12506             v = this.getValue();
12507         }
12508         
12509         if(this.disabled || this.allowBlank || v.length){
12510             this.markValid();
12511             return true;
12512         }
12513         
12514         this.markInvalid();
12515         return false;
12516     },
12517     
12518     tickableInputEl : function()
12519     {
12520         if(!this.tickable || !this.editable){
12521             return this.inputEl();
12522         }
12523         
12524         return this.inputEl().select('.select2-search-field-input', true).first();
12525     }
12526     
12527     
12528
12529     /** 
12530     * @cfg {Boolean} grow 
12531     * @hide 
12532     */
12533     /** 
12534     * @cfg {Number} growMin 
12535     * @hide 
12536     */
12537     /** 
12538     * @cfg {Number} growMax 
12539     * @hide 
12540     */
12541     /**
12542      * @hide
12543      * @method autoSize
12544      */
12545 });
12546 /*
12547  * Based on:
12548  * Ext JS Library 1.1.1
12549  * Copyright(c) 2006-2007, Ext JS, LLC.
12550  *
12551  * Originally Released Under LGPL - original licence link has changed is not relivant.
12552  *
12553  * Fork - LGPL
12554  * <script type="text/javascript">
12555  */
12556
12557 /**
12558  * @class Roo.View
12559  * @extends Roo.util.Observable
12560  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
12561  * This class also supports single and multi selection modes. <br>
12562  * Create a data model bound view:
12563  <pre><code>
12564  var store = new Roo.data.Store(...);
12565
12566  var view = new Roo.View({
12567     el : "my-element",
12568     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
12569  
12570     singleSelect: true,
12571     selectedClass: "ydataview-selected",
12572     store: store
12573  });
12574
12575  // listen for node click?
12576  view.on("click", function(vw, index, node, e){
12577  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12578  });
12579
12580  // load XML data
12581  dataModel.load("foobar.xml");
12582  </code></pre>
12583  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12584  * <br><br>
12585  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12586  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12587  * 
12588  * Note: old style constructor is still suported (container, template, config)
12589  * 
12590  * @constructor
12591  * Create a new View
12592  * @param {Object} config The config object
12593  * 
12594  */
12595 Roo.View = function(config, depreciated_tpl, depreciated_config){
12596     
12597     this.parent = false;
12598     
12599     if (typeof(depreciated_tpl) == 'undefined') {
12600         // new way.. - universal constructor.
12601         Roo.apply(this, config);
12602         this.el  = Roo.get(this.el);
12603     } else {
12604         // old format..
12605         this.el  = Roo.get(config);
12606         this.tpl = depreciated_tpl;
12607         Roo.apply(this, depreciated_config);
12608     }
12609     this.wrapEl  = this.el.wrap().wrap();
12610     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12611     
12612     
12613     if(typeof(this.tpl) == "string"){
12614         this.tpl = new Roo.Template(this.tpl);
12615     } else {
12616         // support xtype ctors..
12617         this.tpl = new Roo.factory(this.tpl, Roo);
12618     }
12619     
12620     
12621     this.tpl.compile();
12622     
12623     /** @private */
12624     this.addEvents({
12625         /**
12626          * @event beforeclick
12627          * Fires before a click is processed. Returns false to cancel the default action.
12628          * @param {Roo.View} this
12629          * @param {Number} index The index of the target node
12630          * @param {HTMLElement} node The target node
12631          * @param {Roo.EventObject} e The raw event object
12632          */
12633             "beforeclick" : true,
12634         /**
12635          * @event click
12636          * Fires when a template node is clicked.
12637          * @param {Roo.View} this
12638          * @param {Number} index The index of the target node
12639          * @param {HTMLElement} node The target node
12640          * @param {Roo.EventObject} e The raw event object
12641          */
12642             "click" : true,
12643         /**
12644          * @event dblclick
12645          * Fires when a template node is double clicked.
12646          * @param {Roo.View} this
12647          * @param {Number} index The index of the target node
12648          * @param {HTMLElement} node The target node
12649          * @param {Roo.EventObject} e The raw event object
12650          */
12651             "dblclick" : true,
12652         /**
12653          * @event contextmenu
12654          * Fires when a template node is right clicked.
12655          * @param {Roo.View} this
12656          * @param {Number} index The index of the target node
12657          * @param {HTMLElement} node The target node
12658          * @param {Roo.EventObject} e The raw event object
12659          */
12660             "contextmenu" : true,
12661         /**
12662          * @event selectionchange
12663          * Fires when the selected nodes change.
12664          * @param {Roo.View} this
12665          * @param {Array} selections Array of the selected nodes
12666          */
12667             "selectionchange" : true,
12668     
12669         /**
12670          * @event beforeselect
12671          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12672          * @param {Roo.View} this
12673          * @param {HTMLElement} node The node to be selected
12674          * @param {Array} selections Array of currently selected nodes
12675          */
12676             "beforeselect" : true,
12677         /**
12678          * @event preparedata
12679          * Fires on every row to render, to allow you to change the data.
12680          * @param {Roo.View} this
12681          * @param {Object} data to be rendered (change this)
12682          */
12683           "preparedata" : true
12684           
12685           
12686         });
12687
12688
12689
12690     this.el.on({
12691         "click": this.onClick,
12692         "dblclick": this.onDblClick,
12693         "contextmenu": this.onContextMenu,
12694         scope:this
12695     });
12696
12697     this.selections = [];
12698     this.nodes = [];
12699     this.cmp = new Roo.CompositeElementLite([]);
12700     if(this.store){
12701         this.store = Roo.factory(this.store, Roo.data);
12702         this.setStore(this.store, true);
12703     }
12704     
12705     if ( this.footer && this.footer.xtype) {
12706            
12707          var fctr = this.wrapEl.appendChild(document.createElement("div"));
12708         
12709         this.footer.dataSource = this.store
12710         this.footer.container = fctr;
12711         this.footer = Roo.factory(this.footer, Roo);
12712         fctr.insertFirst(this.el);
12713         
12714         // this is a bit insane - as the paging toolbar seems to detach the el..
12715 //        dom.parentNode.parentNode.parentNode
12716          // they get detached?
12717     }
12718     
12719     
12720     Roo.View.superclass.constructor.call(this);
12721     
12722     
12723 };
12724
12725 Roo.extend(Roo.View, Roo.util.Observable, {
12726     
12727      /**
12728      * @cfg {Roo.data.Store} store Data store to load data from.
12729      */
12730     store : false,
12731     
12732     /**
12733      * @cfg {String|Roo.Element} el The container element.
12734      */
12735     el : '',
12736     
12737     /**
12738      * @cfg {String|Roo.Template} tpl The template used by this View 
12739      */
12740     tpl : false,
12741     /**
12742      * @cfg {String} dataName the named area of the template to use as the data area
12743      *                          Works with domtemplates roo-name="name"
12744      */
12745     dataName: false,
12746     /**
12747      * @cfg {String} selectedClass The css class to add to selected nodes
12748      */
12749     selectedClass : "x-view-selected",
12750      /**
12751      * @cfg {String} emptyText The empty text to show when nothing is loaded.
12752      */
12753     emptyText : "",
12754     
12755     /**
12756      * @cfg {String} text to display on mask (default Loading)
12757      */
12758     mask : false,
12759     /**
12760      * @cfg {Boolean} multiSelect Allow multiple selection
12761      */
12762     multiSelect : false,
12763     /**
12764      * @cfg {Boolean} singleSelect Allow single selection
12765      */
12766     singleSelect:  false,
12767     
12768     /**
12769      * @cfg {Boolean} toggleSelect - selecting 
12770      */
12771     toggleSelect : false,
12772     
12773     /**
12774      * @cfg {Boolean} tickable - selecting 
12775      */
12776     tickable : false,
12777     
12778     /**
12779      * Returns the element this view is bound to.
12780      * @return {Roo.Element}
12781      */
12782     getEl : function(){
12783         return this.wrapEl;
12784     },
12785     
12786     
12787
12788     /**
12789      * Refreshes the view. - called by datachanged on the store. - do not call directly.
12790      */
12791     refresh : function(){
12792         //Roo.log('refresh');
12793         var t = this.tpl;
12794         
12795         // if we are using something like 'domtemplate', then
12796         // the what gets used is:
12797         // t.applySubtemplate(NAME, data, wrapping data..)
12798         // the outer template then get' applied with
12799         //     the store 'extra data'
12800         // and the body get's added to the
12801         //      roo-name="data" node?
12802         //      <span class='roo-tpl-{name}'></span> ?????
12803         
12804         
12805         
12806         this.clearSelections();
12807         this.el.update("");
12808         var html = [];
12809         var records = this.store.getRange();
12810         if(records.length < 1) {
12811             
12812             // is this valid??  = should it render a template??
12813             
12814             this.el.update(this.emptyText);
12815             return;
12816         }
12817         var el = this.el;
12818         if (this.dataName) {
12819             this.el.update(t.apply(this.store.meta)); //????
12820             el = this.el.child('.roo-tpl-' + this.dataName);
12821         }
12822         
12823         for(var i = 0, len = records.length; i < len; i++){
12824             var data = this.prepareData(records[i].data, i, records[i]);
12825             this.fireEvent("preparedata", this, data, i, records[i]);
12826             
12827             var d = Roo.apply({}, data);
12828             
12829             if(this.tickable){
12830                 Roo.apply(d, {'roo-id' : Roo.id()});
12831                 
12832                 var _this = this;
12833             
12834                 Roo.each(this.parent.item, function(item){
12835                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
12836                         return;
12837                     }
12838                     Roo.apply(d, {'roo-data-checked' : 'checked'});
12839                 });
12840             }
12841             
12842             html[html.length] = Roo.util.Format.trim(
12843                 this.dataName ?
12844                     t.applySubtemplate(this.dataName, d, this.store.meta) :
12845                     t.apply(d)
12846             );
12847         }
12848         
12849         
12850         
12851         el.update(html.join(""));
12852         this.nodes = el.dom.childNodes;
12853         this.updateIndexes(0);
12854     },
12855     
12856
12857     /**
12858      * Function to override to reformat the data that is sent to
12859      * the template for each node.
12860      * DEPRICATED - use the preparedata event handler.
12861      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
12862      * a JSON object for an UpdateManager bound view).
12863      */
12864     prepareData : function(data, index, record)
12865     {
12866         this.fireEvent("preparedata", this, data, index, record);
12867         return data;
12868     },
12869
12870     onUpdate : function(ds, record){
12871         // Roo.log('on update');   
12872         this.clearSelections();
12873         var index = this.store.indexOf(record);
12874         var n = this.nodes[index];
12875         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
12876         n.parentNode.removeChild(n);
12877         this.updateIndexes(index, index);
12878     },
12879
12880     
12881     
12882 // --------- FIXME     
12883     onAdd : function(ds, records, index)
12884     {
12885         //Roo.log(['on Add', ds, records, index] );        
12886         this.clearSelections();
12887         if(this.nodes.length == 0){
12888             this.refresh();
12889             return;
12890         }
12891         var n = this.nodes[index];
12892         for(var i = 0, len = records.length; i < len; i++){
12893             var d = this.prepareData(records[i].data, i, records[i]);
12894             if(n){
12895                 this.tpl.insertBefore(n, d);
12896             }else{
12897                 
12898                 this.tpl.append(this.el, d);
12899             }
12900         }
12901         this.updateIndexes(index);
12902     },
12903
12904     onRemove : function(ds, record, index){
12905        // Roo.log('onRemove');
12906         this.clearSelections();
12907         var el = this.dataName  ?
12908             this.el.child('.roo-tpl-' + this.dataName) :
12909             this.el; 
12910         
12911         el.dom.removeChild(this.nodes[index]);
12912         this.updateIndexes(index);
12913     },
12914
12915     /**
12916      * Refresh an individual node.
12917      * @param {Number} index
12918      */
12919     refreshNode : function(index){
12920         this.onUpdate(this.store, this.store.getAt(index));
12921     },
12922
12923     updateIndexes : function(startIndex, endIndex){
12924         var ns = this.nodes;
12925         startIndex = startIndex || 0;
12926         endIndex = endIndex || ns.length - 1;
12927         for(var i = startIndex; i <= endIndex; i++){
12928             ns[i].nodeIndex = i;
12929         }
12930     },
12931
12932     /**
12933      * Changes the data store this view uses and refresh the view.
12934      * @param {Store} store
12935      */
12936     setStore : function(store, initial){
12937         if(!initial && this.store){
12938             this.store.un("datachanged", this.refresh);
12939             this.store.un("add", this.onAdd);
12940             this.store.un("remove", this.onRemove);
12941             this.store.un("update", this.onUpdate);
12942             this.store.un("clear", this.refresh);
12943             this.store.un("beforeload", this.onBeforeLoad);
12944             this.store.un("load", this.onLoad);
12945             this.store.un("loadexception", this.onLoad);
12946         }
12947         if(store){
12948           
12949             store.on("datachanged", this.refresh, this);
12950             store.on("add", this.onAdd, this);
12951             store.on("remove", this.onRemove, this);
12952             store.on("update", this.onUpdate, this);
12953             store.on("clear", this.refresh, this);
12954             store.on("beforeload", this.onBeforeLoad, this);
12955             store.on("load", this.onLoad, this);
12956             store.on("loadexception", this.onLoad, this);
12957         }
12958         
12959         if(store){
12960             this.refresh();
12961         }
12962     },
12963     /**
12964      * onbeforeLoad - masks the loading area.
12965      *
12966      */
12967     onBeforeLoad : function(store,opts)
12968     {
12969          //Roo.log('onBeforeLoad');   
12970         if (!opts.add) {
12971             this.el.update("");
12972         }
12973         this.el.mask(this.mask ? this.mask : "Loading" ); 
12974     },
12975     onLoad : function ()
12976     {
12977         this.el.unmask();
12978     },
12979     
12980
12981     /**
12982      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
12983      * @param {HTMLElement} node
12984      * @return {HTMLElement} The template node
12985      */
12986     findItemFromChild : function(node){
12987         var el = this.dataName  ?
12988             this.el.child('.roo-tpl-' + this.dataName,true) :
12989             this.el.dom; 
12990         
12991         if(!node || node.parentNode == el){
12992                     return node;
12993             }
12994             var p = node.parentNode;
12995             while(p && p != el){
12996             if(p.parentNode == el){
12997                 return p;
12998             }
12999             p = p.parentNode;
13000         }
13001             return null;
13002     },
13003
13004     /** @ignore */
13005     onClick : function(e){
13006         var item = this.findItemFromChild(e.getTarget());
13007         if(item){
13008             var index = this.indexOf(item);
13009             if(this.onItemClick(item, index, e) !== false){
13010                 this.fireEvent("click", this, index, item, e);
13011             }
13012         }else{
13013             this.clearSelections();
13014         }
13015     },
13016
13017     /** @ignore */
13018     onContextMenu : function(e){
13019         var item = this.findItemFromChild(e.getTarget());
13020         if(item){
13021             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13022         }
13023     },
13024
13025     /** @ignore */
13026     onDblClick : function(e){
13027         var item = this.findItemFromChild(e.getTarget());
13028         if(item){
13029             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13030         }
13031     },
13032
13033     onItemClick : function(item, index, e)
13034     {
13035         if(this.fireEvent("beforeclick", this, index, item, e) === false){
13036             return false;
13037         }
13038         if (this.toggleSelect) {
13039             var m = this.isSelected(item) ? 'unselect' : 'select';
13040             //Roo.log(m);
13041             var _t = this;
13042             _t[m](item, true, false);
13043             return true;
13044         }
13045         if(this.multiSelect || this.singleSelect){
13046             if(this.multiSelect && e.shiftKey && this.lastSelection){
13047                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13048             }else{
13049                 this.select(item, this.multiSelect && e.ctrlKey);
13050                 this.lastSelection = item;
13051             }
13052             
13053             if(!this.tickable){
13054                 e.preventDefault();
13055             }
13056             
13057         }
13058         return true;
13059     },
13060
13061     /**
13062      * Get the number of selected nodes.
13063      * @return {Number}
13064      */
13065     getSelectionCount : function(){
13066         return this.selections.length;
13067     },
13068
13069     /**
13070      * Get the currently selected nodes.
13071      * @return {Array} An array of HTMLElements
13072      */
13073     getSelectedNodes : function(){
13074         return this.selections;
13075     },
13076
13077     /**
13078      * Get the indexes of the selected nodes.
13079      * @return {Array}
13080      */
13081     getSelectedIndexes : function(){
13082         var indexes = [], s = this.selections;
13083         for(var i = 0, len = s.length; i < len; i++){
13084             indexes.push(s[i].nodeIndex);
13085         }
13086         return indexes;
13087     },
13088
13089     /**
13090      * Clear all selections
13091      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13092      */
13093     clearSelections : function(suppressEvent){
13094         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13095             this.cmp.elements = this.selections;
13096             this.cmp.removeClass(this.selectedClass);
13097             this.selections = [];
13098             if(!suppressEvent){
13099                 this.fireEvent("selectionchange", this, this.selections);
13100             }
13101         }
13102     },
13103
13104     /**
13105      * Returns true if the passed node is selected
13106      * @param {HTMLElement/Number} node The node or node index
13107      * @return {Boolean}
13108      */
13109     isSelected : function(node){
13110         var s = this.selections;
13111         if(s.length < 1){
13112             return false;
13113         }
13114         node = this.getNode(node);
13115         return s.indexOf(node) !== -1;
13116     },
13117
13118     /**
13119      * Selects nodes.
13120      * @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
13121      * @param {Boolean} keepExisting (optional) true to keep existing selections
13122      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13123      */
13124     select : function(nodeInfo, keepExisting, suppressEvent){
13125         if(nodeInfo instanceof Array){
13126             if(!keepExisting){
13127                 this.clearSelections(true);
13128             }
13129             for(var i = 0, len = nodeInfo.length; i < len; i++){
13130                 this.select(nodeInfo[i], true, true);
13131             }
13132             return;
13133         } 
13134         var node = this.getNode(nodeInfo);
13135         if(!node || this.isSelected(node)){
13136             return; // already selected.
13137         }
13138         if(!keepExisting){
13139             this.clearSelections(true);
13140         }
13141         
13142         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13143             Roo.fly(node).addClass(this.selectedClass);
13144             this.selections.push(node);
13145             if(!suppressEvent){
13146                 this.fireEvent("selectionchange", this, this.selections);
13147             }
13148         }
13149         
13150         
13151     },
13152       /**
13153      * Unselects nodes.
13154      * @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
13155      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13156      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13157      */
13158     unselect : function(nodeInfo, keepExisting, suppressEvent)
13159     {
13160         if(nodeInfo instanceof Array){
13161             Roo.each(this.selections, function(s) {
13162                 this.unselect(s, nodeInfo);
13163             }, this);
13164             return;
13165         }
13166         var node = this.getNode(nodeInfo);
13167         if(!node || !this.isSelected(node)){
13168             //Roo.log("not selected");
13169             return; // not selected.
13170         }
13171         // fireevent???
13172         var ns = [];
13173         Roo.each(this.selections, function(s) {
13174             if (s == node ) {
13175                 Roo.fly(node).removeClass(this.selectedClass);
13176
13177                 return;
13178             }
13179             ns.push(s);
13180         },this);
13181         
13182         this.selections= ns;
13183         this.fireEvent("selectionchange", this, this.selections);
13184     },
13185
13186     /**
13187      * Gets a template node.
13188      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13189      * @return {HTMLElement} The node or null if it wasn't found
13190      */
13191     getNode : function(nodeInfo){
13192         if(typeof nodeInfo == "string"){
13193             return document.getElementById(nodeInfo);
13194         }else if(typeof nodeInfo == "number"){
13195             return this.nodes[nodeInfo];
13196         }
13197         return nodeInfo;
13198     },
13199
13200     /**
13201      * Gets a range template nodes.
13202      * @param {Number} startIndex
13203      * @param {Number} endIndex
13204      * @return {Array} An array of nodes
13205      */
13206     getNodes : function(start, end){
13207         var ns = this.nodes;
13208         start = start || 0;
13209         end = typeof end == "undefined" ? ns.length - 1 : end;
13210         var nodes = [];
13211         if(start <= end){
13212             for(var i = start; i <= end; i++){
13213                 nodes.push(ns[i]);
13214             }
13215         } else{
13216             for(var i = start; i >= end; i--){
13217                 nodes.push(ns[i]);
13218             }
13219         }
13220         return nodes;
13221     },
13222
13223     /**
13224      * Finds the index of the passed node
13225      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13226      * @return {Number} The index of the node or -1
13227      */
13228     indexOf : function(node){
13229         node = this.getNode(node);
13230         if(typeof node.nodeIndex == "number"){
13231             return node.nodeIndex;
13232         }
13233         var ns = this.nodes;
13234         for(var i = 0, len = ns.length; i < len; i++){
13235             if(ns[i] == node){
13236                 return i;
13237             }
13238         }
13239         return -1;
13240     }
13241 });
13242 /*
13243  * - LGPL
13244  *
13245  * based on jquery fullcalendar
13246  * 
13247  */
13248
13249 Roo.bootstrap = Roo.bootstrap || {};
13250 /**
13251  * @class Roo.bootstrap.Calendar
13252  * @extends Roo.bootstrap.Component
13253  * Bootstrap Calendar class
13254  * @cfg {Boolean} loadMask (true|false) default false
13255  * @cfg {Object} header generate the user specific header of the calendar, default false
13256
13257  * @constructor
13258  * Create a new Container
13259  * @param {Object} config The config object
13260  */
13261
13262
13263
13264 Roo.bootstrap.Calendar = function(config){
13265     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13266      this.addEvents({
13267         /**
13268              * @event select
13269              * Fires when a date is selected
13270              * @param {DatePicker} this
13271              * @param {Date} date The selected date
13272              */
13273         'select': true,
13274         /**
13275              * @event monthchange
13276              * Fires when the displayed month changes 
13277              * @param {DatePicker} this
13278              * @param {Date} date The selected month
13279              */
13280         'monthchange': true,
13281         /**
13282              * @event evententer
13283              * Fires when mouse over an event
13284              * @param {Calendar} this
13285              * @param {event} Event
13286              */
13287         'evententer': true,
13288         /**
13289              * @event eventleave
13290              * Fires when the mouse leaves an
13291              * @param {Calendar} this
13292              * @param {event}
13293              */
13294         'eventleave': true,
13295         /**
13296              * @event eventclick
13297              * Fires when the mouse click an
13298              * @param {Calendar} this
13299              * @param {event}
13300              */
13301         'eventclick': true
13302         
13303     });
13304
13305 };
13306
13307 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
13308     
13309      /**
13310      * @cfg {Number} startDay
13311      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13312      */
13313     startDay : 0,
13314     
13315     loadMask : false,
13316     
13317     header : false,
13318       
13319     getAutoCreate : function(){
13320         
13321         
13322         var fc_button = function(name, corner, style, content ) {
13323             return Roo.apply({},{
13324                 tag : 'span',
13325                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
13326                          (corner.length ?
13327                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13328                             ''
13329                         ),
13330                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13331                 unselectable: 'on'
13332             });
13333         };
13334         
13335         var header = {};
13336         
13337         if(!this.header){
13338             header = {
13339                 tag : 'table',
13340                 cls : 'fc-header',
13341                 style : 'width:100%',
13342                 cn : [
13343                     {
13344                         tag: 'tr',
13345                         cn : [
13346                             {
13347                                 tag : 'td',
13348                                 cls : 'fc-header-left',
13349                                 cn : [
13350                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
13351                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
13352                                     { tag: 'span', cls: 'fc-header-space' },
13353                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
13354
13355
13356                                 ]
13357                             },
13358
13359                             {
13360                                 tag : 'td',
13361                                 cls : 'fc-header-center',
13362                                 cn : [
13363                                     {
13364                                         tag: 'span',
13365                                         cls: 'fc-header-title',
13366                                         cn : {
13367                                             tag: 'H2',
13368                                             html : 'month / year'
13369                                         }
13370                                     }
13371
13372                                 ]
13373                             },
13374                             {
13375                                 tag : 'td',
13376                                 cls : 'fc-header-right',
13377                                 cn : [
13378                               /*      fc_button('month', 'left', '', 'month' ),
13379                                     fc_button('week', '', '', 'week' ),
13380                                     fc_button('day', 'right', '', 'day' )
13381                                 */    
13382
13383                                 ]
13384                             }
13385
13386                         ]
13387                     }
13388                 ]
13389             };
13390         }
13391         
13392         header = this.header;
13393         
13394        
13395         var cal_heads = function() {
13396             var ret = [];
13397             // fixme - handle this.
13398             
13399             for (var i =0; i < Date.dayNames.length; i++) {
13400                 var d = Date.dayNames[i];
13401                 ret.push({
13402                     tag: 'th',
13403                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13404                     html : d.substring(0,3)
13405                 });
13406                 
13407             }
13408             ret[0].cls += ' fc-first';
13409             ret[6].cls += ' fc-last';
13410             return ret;
13411         };
13412         var cal_cell = function(n) {
13413             return  {
13414                 tag: 'td',
13415                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13416                 cn : [
13417                     {
13418                         cn : [
13419                             {
13420                                 cls: 'fc-day-number',
13421                                 html: 'D'
13422                             },
13423                             {
13424                                 cls: 'fc-day-content',
13425                              
13426                                 cn : [
13427                                      {
13428                                         style: 'position: relative;' // height: 17px;
13429                                     }
13430                                 ]
13431                             }
13432                             
13433                             
13434                         ]
13435                     }
13436                 ]
13437                 
13438             }
13439         };
13440         var cal_rows = function() {
13441             
13442             var ret = [];
13443             for (var r = 0; r < 6; r++) {
13444                 var row= {
13445                     tag : 'tr',
13446                     cls : 'fc-week',
13447                     cn : []
13448                 };
13449                 
13450                 for (var i =0; i < Date.dayNames.length; i++) {
13451                     var d = Date.dayNames[i];
13452                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13453
13454                 }
13455                 row.cn[0].cls+=' fc-first';
13456                 row.cn[0].cn[0].style = 'min-height:90px';
13457                 row.cn[6].cls+=' fc-last';
13458                 ret.push(row);
13459                 
13460             }
13461             ret[0].cls += ' fc-first';
13462             ret[4].cls += ' fc-prev-last';
13463             ret[5].cls += ' fc-last';
13464             return ret;
13465             
13466         };
13467         
13468         var cal_table = {
13469             tag: 'table',
13470             cls: 'fc-border-separate',
13471             style : 'width:100%',
13472             cellspacing  : 0,
13473             cn : [
13474                 { 
13475                     tag: 'thead',
13476                     cn : [
13477                         { 
13478                             tag: 'tr',
13479                             cls : 'fc-first fc-last',
13480                             cn : cal_heads()
13481                         }
13482                     ]
13483                 },
13484                 { 
13485                     tag: 'tbody',
13486                     cn : cal_rows()
13487                 }
13488                   
13489             ]
13490         };
13491          
13492          var cfg = {
13493             cls : 'fc fc-ltr',
13494             cn : [
13495                 header,
13496                 {
13497                     cls : 'fc-content',
13498                     style : "position: relative;",
13499                     cn : [
13500                         {
13501                             cls : 'fc-view fc-view-month fc-grid',
13502                             style : 'position: relative',
13503                             unselectable : 'on',
13504                             cn : [
13505                                 {
13506                                     cls : 'fc-event-container',
13507                                     style : 'position:absolute;z-index:8;top:0;left:0;'
13508                                 },
13509                                 cal_table
13510                             ]
13511                         }
13512                     ]
13513     
13514                 }
13515            ] 
13516             
13517         };
13518         
13519          
13520         
13521         return cfg;
13522     },
13523     
13524     
13525     initEvents : function()
13526     {
13527         if(!this.store){
13528             throw "can not find store for calendar";
13529         }
13530         
13531         var mark = {
13532             tag: "div",
13533             cls:"x-dlg-mask",
13534             style: "text-align:center",
13535             cn: [
13536                 {
13537                     tag: "div",
13538                     style: "background-color:white;width:50%;margin:250 auto",
13539                     cn: [
13540                         {
13541                             tag: "img",
13542                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
13543                         },
13544                         {
13545                             tag: "span",
13546                             html: "Loading"
13547                         }
13548                         
13549                     ]
13550                 }
13551             ]
13552         }
13553         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13554         
13555         var size = this.el.select('.fc-content', true).first().getSize();
13556         this.maskEl.setSize(size.width, size.height);
13557         this.maskEl.enableDisplayMode("block");
13558         if(!this.loadMask){
13559             this.maskEl.hide();
13560         }
13561         
13562         this.store = Roo.factory(this.store, Roo.data);
13563         this.store.on('load', this.onLoad, this);
13564         this.store.on('beforeload', this.onBeforeLoad, this);
13565         
13566         this.resize();
13567         
13568         this.cells = this.el.select('.fc-day',true);
13569         //Roo.log(this.cells);
13570         this.textNodes = this.el.query('.fc-day-number');
13571         this.cells.addClassOnOver('fc-state-hover');
13572         
13573         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13574         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13575         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13576         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13577         
13578         this.on('monthchange', this.onMonthChange, this);
13579         
13580         this.update(new Date().clearTime());
13581     },
13582     
13583     resize : function() {
13584         var sz  = this.el.getSize();
13585         
13586         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13587         this.el.select('.fc-day-content div',true).setHeight(34);
13588     },
13589     
13590     
13591     // private
13592     showPrevMonth : function(e){
13593         this.update(this.activeDate.add("mo", -1));
13594     },
13595     showToday : function(e){
13596         this.update(new Date().clearTime());
13597     },
13598     // private
13599     showNextMonth : function(e){
13600         this.update(this.activeDate.add("mo", 1));
13601     },
13602
13603     // private
13604     showPrevYear : function(){
13605         this.update(this.activeDate.add("y", -1));
13606     },
13607
13608     // private
13609     showNextYear : function(){
13610         this.update(this.activeDate.add("y", 1));
13611     },
13612
13613     
13614    // private
13615     update : function(date)
13616     {
13617         var vd = this.activeDate;
13618         this.activeDate = date;
13619 //        if(vd && this.el){
13620 //            var t = date.getTime();
13621 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13622 //                Roo.log('using add remove');
13623 //                
13624 //                this.fireEvent('monthchange', this, date);
13625 //                
13626 //                this.cells.removeClass("fc-state-highlight");
13627 //                this.cells.each(function(c){
13628 //                   if(c.dateValue == t){
13629 //                       c.addClass("fc-state-highlight");
13630 //                       setTimeout(function(){
13631 //                            try{c.dom.firstChild.focus();}catch(e){}
13632 //                       }, 50);
13633 //                       return false;
13634 //                   }
13635 //                   return true;
13636 //                });
13637 //                return;
13638 //            }
13639 //        }
13640         
13641         var days = date.getDaysInMonth();
13642         
13643         var firstOfMonth = date.getFirstDateOfMonth();
13644         var startingPos = firstOfMonth.getDay()-this.startDay;
13645         
13646         if(startingPos < this.startDay){
13647             startingPos += 7;
13648         }
13649         
13650         var pm = date.add(Date.MONTH, -1);
13651         var prevStart = pm.getDaysInMonth()-startingPos;
13652 //        
13653         this.cells = this.el.select('.fc-day',true);
13654         this.textNodes = this.el.query('.fc-day-number');
13655         this.cells.addClassOnOver('fc-state-hover');
13656         
13657         var cells = this.cells.elements;
13658         var textEls = this.textNodes;
13659         
13660         Roo.each(cells, function(cell){
13661             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13662         });
13663         
13664         days += startingPos;
13665
13666         // convert everything to numbers so it's fast
13667         var day = 86400000;
13668         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13669         //Roo.log(d);
13670         //Roo.log(pm);
13671         //Roo.log(prevStart);
13672         
13673         var today = new Date().clearTime().getTime();
13674         var sel = date.clearTime().getTime();
13675         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13676         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13677         var ddMatch = this.disabledDatesRE;
13678         var ddText = this.disabledDatesText;
13679         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13680         var ddaysText = this.disabledDaysText;
13681         var format = this.format;
13682         
13683         var setCellClass = function(cal, cell){
13684             cell.row = 0;
13685             cell.events = [];
13686             cell.more = [];
13687             //Roo.log('set Cell Class');
13688             cell.title = "";
13689             var t = d.getTime();
13690             
13691             //Roo.log(d);
13692             
13693             cell.dateValue = t;
13694             if(t == today){
13695                 cell.className += " fc-today";
13696                 cell.className += " fc-state-highlight";
13697                 cell.title = cal.todayText;
13698             }
13699             if(t == sel){
13700                 // disable highlight in other month..
13701                 //cell.className += " fc-state-highlight";
13702                 
13703             }
13704             // disabling
13705             if(t < min) {
13706                 cell.className = " fc-state-disabled";
13707                 cell.title = cal.minText;
13708                 return;
13709             }
13710             if(t > max) {
13711                 cell.className = " fc-state-disabled";
13712                 cell.title = cal.maxText;
13713                 return;
13714             }
13715             if(ddays){
13716                 if(ddays.indexOf(d.getDay()) != -1){
13717                     cell.title = ddaysText;
13718                     cell.className = " fc-state-disabled";
13719                 }
13720             }
13721             if(ddMatch && format){
13722                 var fvalue = d.dateFormat(format);
13723                 if(ddMatch.test(fvalue)){
13724                     cell.title = ddText.replace("%0", fvalue);
13725                     cell.className = " fc-state-disabled";
13726                 }
13727             }
13728             
13729             if (!cell.initialClassName) {
13730                 cell.initialClassName = cell.dom.className;
13731             }
13732             
13733             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
13734         };
13735
13736         var i = 0;
13737         
13738         for(; i < startingPos; i++) {
13739             textEls[i].innerHTML = (++prevStart);
13740             d.setDate(d.getDate()+1);
13741             
13742             cells[i].className = "fc-past fc-other-month";
13743             setCellClass(this, cells[i]);
13744         }
13745         
13746         var intDay = 0;
13747         
13748         for(; i < days; i++){
13749             intDay = i - startingPos + 1;
13750             textEls[i].innerHTML = (intDay);
13751             d.setDate(d.getDate()+1);
13752             
13753             cells[i].className = ''; // "x-date-active";
13754             setCellClass(this, cells[i]);
13755         }
13756         var extraDays = 0;
13757         
13758         for(; i < 42; i++) {
13759             textEls[i].innerHTML = (++extraDays);
13760             d.setDate(d.getDate()+1);
13761             
13762             cells[i].className = "fc-future fc-other-month";
13763             setCellClass(this, cells[i]);
13764         }
13765         
13766         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13767         
13768         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13769         
13770         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13771         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13772         
13773         if(totalRows != 6){
13774             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13775             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13776         }
13777         
13778         this.fireEvent('monthchange', this, date);
13779         
13780         
13781         /*
13782         if(!this.internalRender){
13783             var main = this.el.dom.firstChild;
13784             var w = main.offsetWidth;
13785             this.el.setWidth(w + this.el.getBorderWidth("lr"));
13786             Roo.fly(main).setWidth(w);
13787             this.internalRender = true;
13788             // opera does not respect the auto grow header center column
13789             // then, after it gets a width opera refuses to recalculate
13790             // without a second pass
13791             if(Roo.isOpera && !this.secondPass){
13792                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13793                 this.secondPass = true;
13794                 this.update.defer(10, this, [date]);
13795             }
13796         }
13797         */
13798         
13799     },
13800     
13801     findCell : function(dt) {
13802         dt = dt.clearTime().getTime();
13803         var ret = false;
13804         this.cells.each(function(c){
13805             //Roo.log("check " +c.dateValue + '?=' + dt);
13806             if(c.dateValue == dt){
13807                 ret = c;
13808                 return false;
13809             }
13810             return true;
13811         });
13812         
13813         return ret;
13814     },
13815     
13816     findCells : function(ev) {
13817         var s = ev.start.clone().clearTime().getTime();
13818        // Roo.log(s);
13819         var e= ev.end.clone().clearTime().getTime();
13820        // Roo.log(e);
13821         var ret = [];
13822         this.cells.each(function(c){
13823              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
13824             
13825             if(c.dateValue > e){
13826                 return ;
13827             }
13828             if(c.dateValue < s){
13829                 return ;
13830             }
13831             ret.push(c);
13832         });
13833         
13834         return ret;    
13835     },
13836     
13837 //    findBestRow: function(cells)
13838 //    {
13839 //        var ret = 0;
13840 //        
13841 //        for (var i =0 ; i < cells.length;i++) {
13842 //            ret  = Math.max(cells[i].rows || 0,ret);
13843 //        }
13844 //        return ret;
13845 //        
13846 //    },
13847     
13848     
13849     addItem : function(ev)
13850     {
13851         // look for vertical location slot in
13852         var cells = this.findCells(ev);
13853         
13854 //        ev.row = this.findBestRow(cells);
13855         
13856         // work out the location.
13857         
13858         var crow = false;
13859         var rows = [];
13860         for(var i =0; i < cells.length; i++) {
13861             
13862             cells[i].row = cells[0].row;
13863             
13864             if(i == 0){
13865                 cells[i].row = cells[i].row + 1;
13866             }
13867             
13868             if (!crow) {
13869                 crow = {
13870                     start : cells[i],
13871                     end :  cells[i]
13872                 };
13873                 continue;
13874             }
13875             if (crow.start.getY() == cells[i].getY()) {
13876                 // on same row.
13877                 crow.end = cells[i];
13878                 continue;
13879             }
13880             // different row.
13881             rows.push(crow);
13882             crow = {
13883                 start: cells[i],
13884                 end : cells[i]
13885             };
13886             
13887         }
13888         
13889         rows.push(crow);
13890         ev.els = [];
13891         ev.rows = rows;
13892         ev.cells = cells;
13893         
13894         cells[0].events.push(ev);
13895         
13896         this.calevents.push(ev);
13897     },
13898     
13899     clearEvents: function() {
13900         
13901         if(!this.calevents){
13902             return;
13903         }
13904         
13905         Roo.each(this.cells.elements, function(c){
13906             c.row = 0;
13907             c.events = [];
13908             c.more = [];
13909         });
13910         
13911         Roo.each(this.calevents, function(e) {
13912             Roo.each(e.els, function(el) {
13913                 el.un('mouseenter' ,this.onEventEnter, this);
13914                 el.un('mouseleave' ,this.onEventLeave, this);
13915                 el.remove();
13916             },this);
13917         },this);
13918         
13919         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
13920             e.remove();
13921         });
13922         
13923     },
13924     
13925     renderEvents: function()
13926     {   
13927         var _this = this;
13928         
13929         this.cells.each(function(c) {
13930             
13931             if(c.row < 5){
13932                 return;
13933             }
13934             
13935             var ev = c.events;
13936             
13937             var r = 4;
13938             if(c.row != c.events.length){
13939                 r = 4 - (4 - (c.row - c.events.length));
13940             }
13941             
13942             c.events = ev.slice(0, r);
13943             c.more = ev.slice(r);
13944             
13945             if(c.more.length && c.more.length == 1){
13946                 c.events.push(c.more.pop());
13947             }
13948             
13949             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
13950             
13951         });
13952             
13953         this.cells.each(function(c) {
13954             
13955             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
13956             
13957             
13958             for (var e = 0; e < c.events.length; e++){
13959                 var ev = c.events[e];
13960                 var rows = ev.rows;
13961                 
13962                 for(var i = 0; i < rows.length; i++) {
13963                 
13964                     // how many rows should it span..
13965
13966                     var  cfg = {
13967                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
13968                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
13969
13970                         unselectable : "on",
13971                         cn : [
13972                             {
13973                                 cls: 'fc-event-inner',
13974                                 cn : [
13975     //                                {
13976     //                                  tag:'span',
13977     //                                  cls: 'fc-event-time',
13978     //                                  html : cells.length > 1 ? '' : ev.time
13979     //                                },
13980                                     {
13981                                       tag:'span',
13982                                       cls: 'fc-event-title',
13983                                       html : String.format('{0}', ev.title)
13984                                     }
13985
13986
13987                                 ]
13988                             },
13989                             {
13990                                 cls: 'ui-resizable-handle ui-resizable-e',
13991                                 html : '&nbsp;&nbsp;&nbsp'
13992                             }
13993
13994                         ]
13995                     };
13996
13997                     if (i == 0) {
13998                         cfg.cls += ' fc-event-start';
13999                     }
14000                     if ((i+1) == rows.length) {
14001                         cfg.cls += ' fc-event-end';
14002                     }
14003
14004                     var ctr = _this.el.select('.fc-event-container',true).first();
14005                     var cg = ctr.createChild(cfg);
14006
14007                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14008                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14009
14010                     var r = (c.more.length) ? 1 : 0;
14011                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
14012                     cg.setWidth(ebox.right - sbox.x -2);
14013
14014                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14015                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14016                     cg.on('click', _this.onEventClick, _this, ev);
14017
14018                     ev.els.push(cg);
14019                     
14020                 }
14021                 
14022             }
14023             
14024             
14025             if(c.more.length){
14026                 var  cfg = {
14027                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14028                     style : 'position: absolute',
14029                     unselectable : "on",
14030                     cn : [
14031                         {
14032                             cls: 'fc-event-inner',
14033                             cn : [
14034                                 {
14035                                   tag:'span',
14036                                   cls: 'fc-event-title',
14037                                   html : 'More'
14038                                 }
14039
14040
14041                             ]
14042                         },
14043                         {
14044                             cls: 'ui-resizable-handle ui-resizable-e',
14045                             html : '&nbsp;&nbsp;&nbsp'
14046                         }
14047
14048                     ]
14049                 };
14050
14051                 var ctr = _this.el.select('.fc-event-container',true).first();
14052                 var cg = ctr.createChild(cfg);
14053
14054                 var sbox = c.select('.fc-day-content',true).first().getBox();
14055                 var ebox = c.select('.fc-day-content',true).first().getBox();
14056                 //Roo.log(cg);
14057                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
14058                 cg.setWidth(ebox.right - sbox.x -2);
14059
14060                 cg.on('click', _this.onMoreEventClick, _this, c.more);
14061                 
14062             }
14063             
14064         });
14065         
14066         
14067         
14068     },
14069     
14070     onEventEnter: function (e, el,event,d) {
14071         this.fireEvent('evententer', this, el, event);
14072     },
14073     
14074     onEventLeave: function (e, el,event,d) {
14075         this.fireEvent('eventleave', this, el, event);
14076     },
14077     
14078     onEventClick: function (e, el,event,d) {
14079         this.fireEvent('eventclick', this, el, event);
14080     },
14081     
14082     onMonthChange: function () {
14083         this.store.load();
14084     },
14085     
14086     onMoreEventClick: function(e, el, more)
14087     {
14088         var _this = this;
14089         
14090         this.calpopover.placement = 'right';
14091         this.calpopover.setTitle('More');
14092         
14093         this.calpopover.setContent('');
14094         
14095         var ctr = this.calpopover.el.select('.popover-content', true).first();
14096         
14097         Roo.each(more, function(m){
14098             var cfg = {
14099                 cls : 'fc-event-hori fc-event-draggable',
14100                 html : m.title
14101             }
14102             var cg = ctr.createChild(cfg);
14103             
14104             cg.on('click', _this.onEventClick, _this, m);
14105         });
14106         
14107         this.calpopover.show(el);
14108         
14109         
14110     },
14111     
14112     onLoad: function () 
14113     {   
14114         this.calevents = [];
14115         var cal = this;
14116         
14117         if(this.store.getCount() > 0){
14118             this.store.data.each(function(d){
14119                cal.addItem({
14120                     id : d.data.id,
14121                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14122                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14123                     time : d.data.start_time,
14124                     title : d.data.title,
14125                     description : d.data.description,
14126                     venue : d.data.venue
14127                 });
14128             });
14129         }
14130         
14131         this.renderEvents();
14132         
14133         if(this.calevents.length && this.loadMask){
14134             this.maskEl.hide();
14135         }
14136     },
14137     
14138     onBeforeLoad: function()
14139     {
14140         this.clearEvents();
14141         if(this.loadMask){
14142             this.maskEl.show();
14143         }
14144     }
14145 });
14146
14147  
14148  /*
14149  * - LGPL
14150  *
14151  * element
14152  * 
14153  */
14154
14155 /**
14156  * @class Roo.bootstrap.Popover
14157  * @extends Roo.bootstrap.Component
14158  * Bootstrap Popover class
14159  * @cfg {String} html contents of the popover   (or false to use children..)
14160  * @cfg {String} title of popover (or false to hide)
14161  * @cfg {String} placement how it is placed
14162  * @cfg {String} trigger click || hover (or false to trigger manually)
14163  * @cfg {String} over what (parent or false to trigger manually.)
14164  * @cfg {Number} delay - delay before showing
14165  
14166  * @constructor
14167  * Create a new Popover
14168  * @param {Object} config The config object
14169  */
14170
14171 Roo.bootstrap.Popover = function(config){
14172     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14173 };
14174
14175 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
14176     
14177     title: 'Fill in a title',
14178     html: false,
14179     
14180     placement : 'right',
14181     trigger : 'hover', // hover
14182     
14183     delay : 0,
14184     
14185     over: 'parent',
14186     
14187     can_build_overlaid : false,
14188     
14189     getChildContainer : function()
14190     {
14191         return this.el.select('.popover-content',true).first();
14192     },
14193     
14194     getAutoCreate : function(){
14195          Roo.log('make popover?');
14196         var cfg = {
14197            cls : 'popover roo-dynamic',
14198            style: 'display:block',
14199            cn : [
14200                 {
14201                     cls : 'arrow'
14202                 },
14203                 {
14204                     cls : 'popover-inner',
14205                     cn : [
14206                         {
14207                             tag: 'h3',
14208                             cls: 'popover-title',
14209                             html : this.title
14210                         },
14211                         {
14212                             cls : 'popover-content',
14213                             html : this.html
14214                         }
14215                     ]
14216                     
14217                 }
14218            ]
14219         };
14220         
14221         return cfg;
14222     },
14223     setTitle: function(str)
14224     {
14225         this.el.select('.popover-title',true).first().dom.innerHTML = str;
14226     },
14227     setContent: function(str)
14228     {
14229         this.el.select('.popover-content',true).first().dom.innerHTML = str;
14230     },
14231     // as it get's added to the bottom of the page.
14232     onRender : function(ct, position)
14233     {
14234         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14235         if(!this.el){
14236             var cfg = Roo.apply({},  this.getAutoCreate());
14237             cfg.id = Roo.id();
14238             
14239             if (this.cls) {
14240                 cfg.cls += ' ' + this.cls;
14241             }
14242             if (this.style) {
14243                 cfg.style = this.style;
14244             }
14245             Roo.log("adding to ")
14246             this.el = Roo.get(document.body).createChild(cfg, position);
14247             Roo.log(this.el);
14248         }
14249         this.initEvents();
14250     },
14251     
14252     initEvents : function()
14253     {
14254         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14255         this.el.enableDisplayMode('block');
14256         this.el.hide();
14257         if (this.over === false) {
14258             return; 
14259         }
14260         if (this.triggers === false) {
14261             return;
14262         }
14263         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14264         var triggers = this.trigger ? this.trigger.split(' ') : [];
14265         Roo.each(triggers, function(trigger) {
14266         
14267             if (trigger == 'click') {
14268                 on_el.on('click', this.toggle, this);
14269             } else if (trigger != 'manual') {
14270                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
14271                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14272       
14273                 on_el.on(eventIn  ,this.enter, this);
14274                 on_el.on(eventOut, this.leave, this);
14275             }
14276         }, this);
14277         
14278     },
14279     
14280     
14281     // private
14282     timeout : null,
14283     hoverState : null,
14284     
14285     toggle : function () {
14286         this.hoverState == 'in' ? this.leave() : this.enter();
14287     },
14288     
14289     enter : function () {
14290        
14291     
14292         clearTimeout(this.timeout);
14293     
14294         this.hoverState = 'in';
14295     
14296         if (!this.delay || !this.delay.show) {
14297             this.show();
14298             return;
14299         }
14300         var _t = this;
14301         this.timeout = setTimeout(function () {
14302             if (_t.hoverState == 'in') {
14303                 _t.show();
14304             }
14305         }, this.delay.show)
14306     },
14307     leave : function() {
14308         clearTimeout(this.timeout);
14309     
14310         this.hoverState = 'out';
14311     
14312         if (!this.delay || !this.delay.hide) {
14313             this.hide();
14314             return;
14315         }
14316         var _t = this;
14317         this.timeout = setTimeout(function () {
14318             if (_t.hoverState == 'out') {
14319                 _t.hide();
14320             }
14321         }, this.delay.hide)
14322     },
14323     
14324     show : function (on_el)
14325     {
14326         if (!on_el) {
14327             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14328         }
14329         // set content.
14330         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14331         if (this.html !== false) {
14332             this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14333         }
14334         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14335         if (!this.title.length) {
14336             this.el.select('.popover-title',true).hide();
14337         }
14338         
14339         var placement = typeof this.placement == 'function' ?
14340             this.placement.call(this, this.el, on_el) :
14341             this.placement;
14342             
14343         var autoToken = /\s?auto?\s?/i;
14344         var autoPlace = autoToken.test(placement);
14345         if (autoPlace) {
14346             placement = placement.replace(autoToken, '') || 'top';
14347         }
14348         
14349         //this.el.detach()
14350         //this.el.setXY([0,0]);
14351         this.el.show();
14352         this.el.dom.style.display='block';
14353         this.el.addClass(placement);
14354         
14355         //this.el.appendTo(on_el);
14356         
14357         var p = this.getPosition();
14358         var box = this.el.getBox();
14359         
14360         if (autoPlace) {
14361             // fixme..
14362         }
14363         var align = Roo.bootstrap.Popover.alignment[placement];
14364         this.el.alignTo(on_el, align[0],align[1]);
14365         //var arrow = this.el.select('.arrow',true).first();
14366         //arrow.set(align[2], 
14367         
14368         this.el.addClass('in');
14369         this.hoverState = null;
14370         
14371         if (this.el.hasClass('fade')) {
14372             // fade it?
14373         }
14374         
14375     },
14376     hide : function()
14377     {
14378         this.el.setXY([0,0]);
14379         this.el.removeClass('in');
14380         this.el.hide();
14381         
14382     }
14383     
14384 });
14385
14386 Roo.bootstrap.Popover.alignment = {
14387     'left' : ['r-l', [-10,0], 'right'],
14388     'right' : ['l-r', [10,0], 'left'],
14389     'bottom' : ['t-b', [0,10], 'top'],
14390     'top' : [ 'b-t', [0,-10], 'bottom']
14391 };
14392
14393  /*
14394  * - LGPL
14395  *
14396  * Progress
14397  * 
14398  */
14399
14400 /**
14401  * @class Roo.bootstrap.Progress
14402  * @extends Roo.bootstrap.Component
14403  * Bootstrap Progress class
14404  * @cfg {Boolean} striped striped of the progress bar
14405  * @cfg {Boolean} active animated of the progress bar
14406  * 
14407  * 
14408  * @constructor
14409  * Create a new Progress
14410  * @param {Object} config The config object
14411  */
14412
14413 Roo.bootstrap.Progress = function(config){
14414     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14415 };
14416
14417 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
14418     
14419     striped : false,
14420     active: false,
14421     
14422     getAutoCreate : function(){
14423         var cfg = {
14424             tag: 'div',
14425             cls: 'progress'
14426         };
14427         
14428         
14429         if(this.striped){
14430             cfg.cls += ' progress-striped';
14431         }
14432       
14433         if(this.active){
14434             cfg.cls += ' active';
14435         }
14436         
14437         
14438         return cfg;
14439     }
14440    
14441 });
14442
14443  
14444
14445  /*
14446  * - LGPL
14447  *
14448  * ProgressBar
14449  * 
14450  */
14451
14452 /**
14453  * @class Roo.bootstrap.ProgressBar
14454  * @extends Roo.bootstrap.Component
14455  * Bootstrap ProgressBar class
14456  * @cfg {Number} aria_valuenow aria-value now
14457  * @cfg {Number} aria_valuemin aria-value min
14458  * @cfg {Number} aria_valuemax aria-value max
14459  * @cfg {String} label label for the progress bar
14460  * @cfg {String} panel (success | info | warning | danger )
14461  * @cfg {String} role role of the progress bar
14462  * @cfg {String} sr_only text
14463  * 
14464  * 
14465  * @constructor
14466  * Create a new ProgressBar
14467  * @param {Object} config The config object
14468  */
14469
14470 Roo.bootstrap.ProgressBar = function(config){
14471     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14472 };
14473
14474 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
14475     
14476     aria_valuenow : 0,
14477     aria_valuemin : 0,
14478     aria_valuemax : 100,
14479     label : false,
14480     panel : false,
14481     role : false,
14482     sr_only: false,
14483     
14484     getAutoCreate : function()
14485     {
14486         
14487         var cfg = {
14488             tag: 'div',
14489             cls: 'progress-bar',
14490             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14491         };
14492         
14493         if(this.sr_only){
14494             cfg.cn = {
14495                 tag: 'span',
14496                 cls: 'sr-only',
14497                 html: this.sr_only
14498             }
14499         }
14500         
14501         if(this.role){
14502             cfg.role = this.role;
14503         }
14504         
14505         if(this.aria_valuenow){
14506             cfg['aria-valuenow'] = this.aria_valuenow;
14507         }
14508         
14509         if(this.aria_valuemin){
14510             cfg['aria-valuemin'] = this.aria_valuemin;
14511         }
14512         
14513         if(this.aria_valuemax){
14514             cfg['aria-valuemax'] = this.aria_valuemax;
14515         }
14516         
14517         if(this.label && !this.sr_only){
14518             cfg.html = this.label;
14519         }
14520         
14521         if(this.panel){
14522             cfg.cls += ' progress-bar-' + this.panel;
14523         }
14524         
14525         return cfg;
14526     },
14527     
14528     update : function(aria_valuenow)
14529     {
14530         this.aria_valuenow = aria_valuenow;
14531         
14532         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14533     }
14534    
14535 });
14536
14537  
14538
14539  /*
14540  * - LGPL
14541  *
14542  * column
14543  * 
14544  */
14545
14546 /**
14547  * @class Roo.bootstrap.TabGroup
14548  * @extends Roo.bootstrap.Column
14549  * Bootstrap Column class
14550  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14551  * @cfg {Boolean} carousel true to make the group behave like a carousel
14552  * @cfg {Number} showPointer show the panel pointer.. default 0
14553  * 
14554  * @constructor
14555  * Create a new TabGroup
14556  * @param {Object} config The config object
14557  */
14558
14559 Roo.bootstrap.TabGroup = function(config){
14560     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14561     if (!this.navId) {
14562         this.navId = Roo.id();
14563     }
14564     this.tabs = [];
14565     Roo.bootstrap.TabGroup.register(this);
14566     
14567 };
14568
14569 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
14570     
14571     carousel : false,
14572     transition : false,
14573     showPointer : 0,
14574      
14575     getAutoCreate : function()
14576     {
14577         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14578         
14579         cfg.cls += ' tab-content';
14580         
14581         if (this.carousel) {
14582             cfg.cls += ' carousel slide';
14583             cfg.cn = [{
14584                cls : 'carousel-inner'
14585             }]
14586         }
14587         
14588         if(showPointer > 0){
14589             
14590         }
14591         
14592         
14593         return cfg;
14594     },
14595     getChildContainer : function()
14596     {
14597         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14598     },
14599     
14600     /**
14601     * register a Navigation item
14602     * @param {Roo.bootstrap.NavItem} the navitem to add
14603     */
14604     register : function(item)
14605     {
14606         this.tabs.push( item);
14607         item.navId = this.navId; // not really needed..
14608     
14609     },
14610     
14611     getActivePanel : function()
14612     {
14613         var r = false;
14614         Roo.each(this.tabs, function(t) {
14615             if (t.active) {
14616                 r = t;
14617                 return false;
14618             }
14619             return null;
14620         });
14621         return r;
14622         
14623     },
14624     getPanelByName : function(n)
14625     {
14626         var r = false;
14627         Roo.each(this.tabs, function(t) {
14628             if (t.tabId == n) {
14629                 r = t;
14630                 return false;
14631             }
14632             return null;
14633         });
14634         return r;
14635     },
14636     indexOfPanel : function(p)
14637     {
14638         var r = false;
14639         Roo.each(this.tabs, function(t,i) {
14640             if (t.tabId == p.tabId) {
14641                 r = i;
14642                 return false;
14643             }
14644             return null;
14645         });
14646         return r;
14647     },
14648     /**
14649      * show a specific panel
14650      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14651      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14652      */
14653     showPanel : function (pan)
14654     {
14655         
14656         if (typeof(pan) == 'number') {
14657             pan = this.tabs[pan];
14658         }
14659         if (typeof(pan) == 'string') {
14660             pan = this.getPanelByName(pan);
14661         }
14662         if (pan.tabId == this.getActivePanel().tabId) {
14663             return true;
14664         }
14665         var cur = this.getActivePanel();
14666         
14667         if (false === cur.fireEvent('beforedeactivate')) {
14668             return false;
14669         }
14670         
14671         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14672             
14673             this.transition = true;
14674             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
14675             var lr = dir == 'next' ? 'left' : 'right';
14676             pan.el.addClass(dir); // or prev
14677             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14678             cur.el.addClass(lr); // or right
14679             pan.el.addClass(lr);
14680             
14681             var _this = this;
14682             cur.el.on('transitionend', function() {
14683                 Roo.log("trans end?");
14684                 
14685                 pan.el.removeClass([lr,dir]);
14686                 pan.setActive(true);
14687                 
14688                 cur.el.removeClass([lr]);
14689                 cur.setActive(false);
14690                 
14691                 _this.transition = false;
14692                 
14693             }, this, { single:  true } );
14694             return true;
14695         }
14696         
14697         cur.setActive(false);
14698         pan.setActive(true);
14699         return true;
14700         
14701     },
14702     showPanelNext : function()
14703     {
14704         var i = this.indexOfPanel(this.getActivePanel());
14705         if (i > this.tabs.length) {
14706             return;
14707         }
14708         this.showPanel(this.tabs[i+1]);
14709     },
14710     showPanelPrev : function()
14711     {
14712         var i = this.indexOfPanel(this.getActivePanel());
14713         if (i  < 1) {
14714             return;
14715         }
14716         this.showPanel(this.tabs[i-1]);
14717     }
14718     
14719     
14720   
14721 });
14722
14723  
14724
14725  
14726  
14727 Roo.apply(Roo.bootstrap.TabGroup, {
14728     
14729     groups: {},
14730      /**
14731     * register a Navigation Group
14732     * @param {Roo.bootstrap.NavGroup} the navgroup to add
14733     */
14734     register : function(navgrp)
14735     {
14736         this.groups[navgrp.navId] = navgrp;
14737         
14738     },
14739     /**
14740     * fetch a Navigation Group based on the navigation ID
14741     * if one does not exist , it will get created.
14742     * @param {string} the navgroup to add
14743     * @returns {Roo.bootstrap.NavGroup} the navgroup 
14744     */
14745     get: function(navId) {
14746         if (typeof(this.groups[navId]) == 'undefined') {
14747             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
14748         }
14749         return this.groups[navId] ;
14750     }
14751     
14752     
14753     
14754 });
14755
14756  /*
14757  * - LGPL
14758  *
14759  * TabPanel
14760  * 
14761  */
14762
14763 /**
14764  * @class Roo.bootstrap.TabPanel
14765  * @extends Roo.bootstrap.Component
14766  * Bootstrap TabPanel class
14767  * @cfg {Boolean} active panel active
14768  * @cfg {String} html panel content
14769  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
14770  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
14771  * 
14772  * 
14773  * @constructor
14774  * Create a new TabPanel
14775  * @param {Object} config The config object
14776  */
14777
14778 Roo.bootstrap.TabPanel = function(config){
14779     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
14780     this.addEvents({
14781         /**
14782              * @event changed
14783              * Fires when the active status changes
14784              * @param {Roo.bootstrap.TabPanel} this
14785              * @param {Boolean} state the new state
14786             
14787          */
14788         'changed': true,
14789         /**
14790              * @event beforedeactivate
14791              * Fires before a tab is de-activated - can be used to do validation on a form.
14792              * @param {Roo.bootstrap.TabPanel} this
14793              * @return {Boolean} false if there is an error
14794             
14795          */
14796         'beforedeactivate': true
14797      });
14798     
14799     this.tabId = this.tabId || Roo.id();
14800   
14801 };
14802
14803 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
14804     
14805     active: false,
14806     html: false,
14807     tabId: false,
14808     navId : false,
14809     
14810     getAutoCreate : function(){
14811         var cfg = {
14812             tag: 'div',
14813             // item is needed for carousel - not sure if it has any effect otherwise
14814             cls: 'tab-pane item',
14815             html: this.html || ''
14816         };
14817         
14818         if(this.active){
14819             cfg.cls += ' active';
14820         }
14821         
14822         if(this.tabId){
14823             cfg.tabId = this.tabId;
14824         }
14825         
14826         
14827         return cfg;
14828     },
14829     
14830     initEvents:  function()
14831     {
14832         Roo.log('-------- init events on tab panel ---------');
14833         
14834         var p = this.parent();
14835         this.navId = this.navId || p.navId;
14836         
14837         if (typeof(this.navId) != 'undefined') {
14838             // not really needed.. but just in case.. parent should be a NavGroup.
14839             var tg = Roo.bootstrap.TabGroup.get(this.navId);
14840             Roo.log(['register', tg, this]);
14841             tg.register(this);
14842         }
14843     },
14844     
14845     
14846     onRender : function(ct, position)
14847     {
14848        // Roo.log("Call onRender: " + this.xtype);
14849         
14850         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
14851         
14852         
14853         
14854         
14855         
14856     },
14857     
14858     setActive: function(state)
14859     {
14860         Roo.log("panel - set active " + this.tabId + "=" + state);
14861         
14862         this.active = state;
14863         if (!state) {
14864             this.el.removeClass('active');
14865             
14866         } else  if (!this.el.hasClass('active')) {
14867             this.el.addClass('active');
14868         }
14869         this.fireEvent('changed', this, state);
14870     }
14871     
14872     
14873 });
14874  
14875
14876  
14877
14878  /*
14879  * - LGPL
14880  *
14881  * DateField
14882  * 
14883  */
14884
14885 /**
14886  * @class Roo.bootstrap.DateField
14887  * @extends Roo.bootstrap.Input
14888  * Bootstrap DateField class
14889  * @cfg {Number} weekStart default 0
14890  * @cfg {String} viewMode default empty, (months|years)
14891  * @cfg {String} minViewMode default empty, (months|years)
14892  * @cfg {Number} startDate default -Infinity
14893  * @cfg {Number} endDate default Infinity
14894  * @cfg {Boolean} todayHighlight default false
14895  * @cfg {Boolean} todayBtn default false
14896  * @cfg {Boolean} calendarWeeks default false
14897  * @cfg {Object} daysOfWeekDisabled default empty
14898  * @cfg {Boolean} singleMode default false (true | false)
14899  * 
14900  * @cfg {Boolean} keyboardNavigation default true
14901  * @cfg {String} language default en
14902  * 
14903  * @constructor
14904  * Create a new DateField
14905  * @param {Object} config The config object
14906  */
14907
14908 Roo.bootstrap.DateField = function(config){
14909     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
14910      this.addEvents({
14911             /**
14912              * @event show
14913              * Fires when this field show.
14914              * @param {Roo.bootstrap.DateField} this
14915              * @param {Mixed} date The date value
14916              */
14917             show : true,
14918             /**
14919              * @event show
14920              * Fires when this field hide.
14921              * @param {Roo.bootstrap.DateField} this
14922              * @param {Mixed} date The date value
14923              */
14924             hide : true,
14925             /**
14926              * @event select
14927              * Fires when select a date.
14928              * @param {Roo.bootstrap.DateField} this
14929              * @param {Mixed} date The date value
14930              */
14931             select : true
14932         });
14933 };
14934
14935 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
14936     
14937     /**
14938      * @cfg {String} format
14939      * The default date format string which can be overriden for localization support.  The format must be
14940      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
14941      */
14942     format : "m/d/y",
14943     /**
14944      * @cfg {String} altFormats
14945      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
14946      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
14947      */
14948     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
14949     
14950     weekStart : 0,
14951     
14952     viewMode : '',
14953     
14954     minViewMode : '',
14955     
14956     todayHighlight : false,
14957     
14958     todayBtn: false,
14959     
14960     language: 'en',
14961     
14962     keyboardNavigation: true,
14963     
14964     calendarWeeks: false,
14965     
14966     startDate: -Infinity,
14967     
14968     endDate: Infinity,
14969     
14970     daysOfWeekDisabled: [],
14971     
14972     _events: [],
14973     
14974     singleMode : false,
14975     
14976     UTCDate: function()
14977     {
14978         return new Date(Date.UTC.apply(Date, arguments));
14979     },
14980     
14981     UTCToday: function()
14982     {
14983         var today = new Date();
14984         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
14985     },
14986     
14987     getDate: function() {
14988             var d = this.getUTCDate();
14989             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
14990     },
14991     
14992     getUTCDate: function() {
14993             return this.date;
14994     },
14995     
14996     setDate: function(d) {
14997             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
14998     },
14999     
15000     setUTCDate: function(d) {
15001             this.date = d;
15002             this.setValue(this.formatDate(this.date));
15003     },
15004         
15005     onRender: function(ct, position)
15006     {
15007         
15008         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15009         
15010         this.language = this.language || 'en';
15011         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15012         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15013         
15014         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15015         this.format = this.format || 'm/d/y';
15016         this.isInline = false;
15017         this.isInput = true;
15018         this.component = this.el.select('.add-on', true).first() || false;
15019         this.component = (this.component && this.component.length === 0) ? false : this.component;
15020         this.hasInput = this.component && this.inputEL().length;
15021         
15022         if (typeof(this.minViewMode === 'string')) {
15023             switch (this.minViewMode) {
15024                 case 'months':
15025                     this.minViewMode = 1;
15026                     break;
15027                 case 'years':
15028                     this.minViewMode = 2;
15029                     break;
15030                 default:
15031                     this.minViewMode = 0;
15032                     break;
15033             }
15034         }
15035         
15036         if (typeof(this.viewMode === 'string')) {
15037             switch (this.viewMode) {
15038                 case 'months':
15039                     this.viewMode = 1;
15040                     break;
15041                 case 'years':
15042                     this.viewMode = 2;
15043                     break;
15044                 default:
15045                     this.viewMode = 0;
15046                     break;
15047             }
15048         }
15049                 
15050         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15051         
15052 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15053         
15054         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15055         
15056         this.picker().on('mousedown', this.onMousedown, this);
15057         this.picker().on('click', this.onClick, this);
15058         
15059         this.picker().addClass('datepicker-dropdown');
15060         
15061         this.startViewMode = this.viewMode;
15062         
15063         if(this.singleMode){
15064             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15065                 v.setVisibilityMode(Roo.Element.DISPLAY)
15066                 v.hide();
15067             });
15068             
15069             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15070                 v.setStyle('width', '189px');
15071             });
15072         }
15073         
15074         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15075             if(!this.calendarWeeks){
15076                 v.remove();
15077                 return;
15078             }
15079             
15080             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15081             v.attr('colspan', function(i, val){
15082                 return parseInt(val) + 1;
15083             });
15084         })
15085                         
15086         
15087         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15088         
15089         this.setStartDate(this.startDate);
15090         this.setEndDate(this.endDate);
15091         
15092         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15093         
15094         this.fillDow();
15095         this.fillMonths();
15096         this.update();
15097         this.showMode();
15098         
15099         if(this.isInline) {
15100             this.show();
15101         }
15102     },
15103     
15104     picker : function()
15105     {
15106         return this.pickerEl;
15107 //        return this.el.select('.datepicker', true).first();
15108     },
15109     
15110     fillDow: function()
15111     {
15112         var dowCnt = this.weekStart;
15113         
15114         var dow = {
15115             tag: 'tr',
15116             cn: [
15117                 
15118             ]
15119         };
15120         
15121         if(this.calendarWeeks){
15122             dow.cn.push({
15123                 tag: 'th',
15124                 cls: 'cw',
15125                 html: '&nbsp;'
15126             })
15127         }
15128         
15129         while (dowCnt < this.weekStart + 7) {
15130             dow.cn.push({
15131                 tag: 'th',
15132                 cls: 'dow',
15133                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15134             });
15135         }
15136         
15137         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15138     },
15139     
15140     fillMonths: function()
15141     {    
15142         var i = 0;
15143         var months = this.picker().select('>.datepicker-months td', true).first();
15144         
15145         months.dom.innerHTML = '';
15146         
15147         while (i < 12) {
15148             var month = {
15149                 tag: 'span',
15150                 cls: 'month',
15151                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15152             }
15153             
15154             months.createChild(month);
15155         }
15156         
15157     },
15158     
15159     update: function()
15160     {
15161         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;
15162         
15163         if (this.date < this.startDate) {
15164             this.viewDate = new Date(this.startDate);
15165         } else if (this.date > this.endDate) {
15166             this.viewDate = new Date(this.endDate);
15167         } else {
15168             this.viewDate = new Date(this.date);
15169         }
15170         
15171         this.fill();
15172     },
15173     
15174     fill: function() 
15175     {
15176         var d = new Date(this.viewDate),
15177                 year = d.getUTCFullYear(),
15178                 month = d.getUTCMonth(),
15179                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15180                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15181                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15182                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15183                 currentDate = this.date && this.date.valueOf(),
15184                 today = this.UTCToday();
15185         
15186         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15187         
15188 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15189         
15190 //        this.picker.select('>tfoot th.today').
15191 //                                              .text(dates[this.language].today)
15192 //                                              .toggle(this.todayBtn !== false);
15193     
15194         this.updateNavArrows();
15195         this.fillMonths();
15196                                                 
15197         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15198         
15199         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15200          
15201         prevMonth.setUTCDate(day);
15202         
15203         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15204         
15205         var nextMonth = new Date(prevMonth);
15206         
15207         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15208         
15209         nextMonth = nextMonth.valueOf();
15210         
15211         var fillMonths = false;
15212         
15213         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15214         
15215         while(prevMonth.valueOf() < nextMonth) {
15216             var clsName = '';
15217             
15218             if (prevMonth.getUTCDay() === this.weekStart) {
15219                 if(fillMonths){
15220                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15221                 }
15222                     
15223                 fillMonths = {
15224                     tag: 'tr',
15225                     cn: []
15226                 };
15227                 
15228                 if(this.calendarWeeks){
15229                     // ISO 8601: First week contains first thursday.
15230                     // ISO also states week starts on Monday, but we can be more abstract here.
15231                     var
15232                     // Start of current week: based on weekstart/current date
15233                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15234                     // Thursday of this week
15235                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15236                     // First Thursday of year, year from thursday
15237                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15238                     // Calendar week: ms between thursdays, div ms per day, div 7 days
15239                     calWeek =  (th - yth) / 864e5 / 7 + 1;
15240                     
15241                     fillMonths.cn.push({
15242                         tag: 'td',
15243                         cls: 'cw',
15244                         html: calWeek
15245                     });
15246                 }
15247             }
15248             
15249             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15250                 clsName += ' old';
15251             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15252                 clsName += ' new';
15253             }
15254             if (this.todayHighlight &&
15255                 prevMonth.getUTCFullYear() == today.getFullYear() &&
15256                 prevMonth.getUTCMonth() == today.getMonth() &&
15257                 prevMonth.getUTCDate() == today.getDate()) {
15258                 clsName += ' today';
15259             }
15260             
15261             if (currentDate && prevMonth.valueOf() === currentDate) {
15262                 clsName += ' active';
15263             }
15264             
15265             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15266                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15267                     clsName += ' disabled';
15268             }
15269             
15270             fillMonths.cn.push({
15271                 tag: 'td',
15272                 cls: 'day ' + clsName,
15273                 html: prevMonth.getDate()
15274             })
15275             
15276             prevMonth.setDate(prevMonth.getDate()+1);
15277         }
15278           
15279         var currentYear = this.date && this.date.getUTCFullYear();
15280         var currentMonth = this.date && this.date.getUTCMonth();
15281         
15282         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15283         
15284         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15285             v.removeClass('active');
15286             
15287             if(currentYear === year && k === currentMonth){
15288                 v.addClass('active');
15289             }
15290             
15291             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15292                 v.addClass('disabled');
15293             }
15294             
15295         });
15296         
15297         
15298         year = parseInt(year/10, 10) * 10;
15299         
15300         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15301         
15302         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15303         
15304         year -= 1;
15305         for (var i = -1; i < 11; i++) {
15306             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15307                 tag: 'span',
15308                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15309                 html: year
15310             })
15311             
15312             year += 1;
15313         }
15314     },
15315     
15316     showMode: function(dir) 
15317     {
15318         if (dir) {
15319             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15320         }
15321         
15322         Roo.each(this.picker().select('>div',true).elements, function(v){
15323             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15324             v.hide();
15325         });
15326         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15327     },
15328     
15329     place: function()
15330     {
15331         if(this.isInline) return;
15332         
15333         this.picker().removeClass(['bottom', 'top']);
15334         
15335         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15336             /*
15337              * place to the top of element!
15338              *
15339              */
15340             
15341             this.picker().addClass('top');
15342             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15343             
15344             return;
15345         }
15346         
15347         this.picker().addClass('bottom');
15348         
15349         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15350     },
15351     
15352     parseDate : function(value)
15353     {
15354         if(!value || value instanceof Date){
15355             return value;
15356         }
15357         var v = Date.parseDate(value, this.format);
15358         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15359             v = Date.parseDate(value, 'Y-m-d');
15360         }
15361         if(!v && this.altFormats){
15362             if(!this.altFormatsArray){
15363                 this.altFormatsArray = this.altFormats.split("|");
15364             }
15365             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15366                 v = Date.parseDate(value, this.altFormatsArray[i]);
15367             }
15368         }
15369         return v;
15370     },
15371     
15372     formatDate : function(date, fmt)
15373     {   
15374         return (!date || !(date instanceof Date)) ?
15375         date : date.dateFormat(fmt || this.format);
15376     },
15377     
15378     onFocus : function()
15379     {
15380         Roo.bootstrap.DateField.superclass.onFocus.call(this);
15381         this.show();
15382     },
15383     
15384     onBlur : function()
15385     {
15386         Roo.bootstrap.DateField.superclass.onBlur.call(this);
15387         
15388         var d = this.inputEl().getValue();
15389         
15390         this.setValue(d);
15391                 
15392         this.hide();
15393     },
15394     
15395     show : function()
15396     {
15397         this.picker().show();
15398         this.update();
15399         this.place();
15400         
15401         this.fireEvent('show', this, this.date);
15402     },
15403     
15404     hide : function()
15405     {
15406         if(this.isInline) return;
15407         this.picker().hide();
15408         this.viewMode = this.startViewMode;
15409         this.showMode();
15410         
15411         this.fireEvent('hide', this, this.date);
15412         
15413     },
15414     
15415     onMousedown: function(e)
15416     {
15417         e.stopPropagation();
15418         e.preventDefault();
15419     },
15420     
15421     keyup: function(e)
15422     {
15423         Roo.bootstrap.DateField.superclass.keyup.call(this);
15424         this.update();
15425     },
15426
15427     setValue: function(v)
15428     {
15429         
15430         // v can be a string or a date..
15431         
15432         
15433         var d = new Date(this.parseDate(v) ).clearTime();
15434         
15435         if(isNaN(d.getTime())){
15436             this.date = this.viewDate = '';
15437             Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15438             return;
15439         }
15440         
15441         v = this.formatDate(d);
15442         
15443         Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15444         
15445         this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15446      
15447         this.update();
15448
15449         this.fireEvent('select', this, this.date);
15450         
15451     },
15452     
15453     getValue: function()
15454     {
15455         return this.formatDate(this.date);
15456     },
15457     
15458     fireKey: function(e)
15459     {
15460         if (!this.picker().isVisible()){
15461             if (e.keyCode == 27) // allow escape to hide and re-show picker
15462                 this.show();
15463             return;
15464         }
15465         
15466         var dateChanged = false,
15467         dir, day, month,
15468         newDate, newViewDate;
15469         
15470         switch(e.keyCode){
15471             case 27: // escape
15472                 this.hide();
15473                 e.preventDefault();
15474                 break;
15475             case 37: // left
15476             case 39: // right
15477                 if (!this.keyboardNavigation) break;
15478                 dir = e.keyCode == 37 ? -1 : 1;
15479                 
15480                 if (e.ctrlKey){
15481                     newDate = this.moveYear(this.date, dir);
15482                     newViewDate = this.moveYear(this.viewDate, dir);
15483                 } else if (e.shiftKey){
15484                     newDate = this.moveMonth(this.date, dir);
15485                     newViewDate = this.moveMonth(this.viewDate, dir);
15486                 } else {
15487                     newDate = new Date(this.date);
15488                     newDate.setUTCDate(this.date.getUTCDate() + dir);
15489                     newViewDate = new Date(this.viewDate);
15490                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15491                 }
15492                 if (this.dateWithinRange(newDate)){
15493                     this.date = newDate;
15494                     this.viewDate = newViewDate;
15495                     this.setValue(this.formatDate(this.date));
15496 //                    this.update();
15497                     e.preventDefault();
15498                     dateChanged = true;
15499                 }
15500                 break;
15501             case 38: // up
15502             case 40: // down
15503                 if (!this.keyboardNavigation) break;
15504                 dir = e.keyCode == 38 ? -1 : 1;
15505                 if (e.ctrlKey){
15506                     newDate = this.moveYear(this.date, dir);
15507                     newViewDate = this.moveYear(this.viewDate, dir);
15508                 } else if (e.shiftKey){
15509                     newDate = this.moveMonth(this.date, dir);
15510                     newViewDate = this.moveMonth(this.viewDate, dir);
15511                 } else {
15512                     newDate = new Date(this.date);
15513                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15514                     newViewDate = new Date(this.viewDate);
15515                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15516                 }
15517                 if (this.dateWithinRange(newDate)){
15518                     this.date = newDate;
15519                     this.viewDate = newViewDate;
15520                     this.setValue(this.formatDate(this.date));
15521 //                    this.update();
15522                     e.preventDefault();
15523                     dateChanged = true;
15524                 }
15525                 break;
15526             case 13: // enter
15527                 this.setValue(this.formatDate(this.date));
15528                 this.hide();
15529                 e.preventDefault();
15530                 break;
15531             case 9: // tab
15532                 this.setValue(this.formatDate(this.date));
15533                 this.hide();
15534                 break;
15535             case 16: // shift
15536             case 17: // ctrl
15537             case 18: // alt
15538                 break;
15539             default :
15540                 this.hide();
15541                 
15542         }
15543     },
15544     
15545     
15546     onClick: function(e) 
15547     {
15548         e.stopPropagation();
15549         e.preventDefault();
15550         
15551         var target = e.getTarget();
15552         
15553         if(target.nodeName.toLowerCase() === 'i'){
15554             target = Roo.get(target).dom.parentNode;
15555         }
15556         
15557         var nodeName = target.nodeName;
15558         var className = target.className;
15559         var html = target.innerHTML;
15560         //Roo.log(nodeName);
15561         
15562         switch(nodeName.toLowerCase()) {
15563             case 'th':
15564                 switch(className) {
15565                     case 'switch':
15566                         this.showMode(1);
15567                         break;
15568                     case 'prev':
15569                     case 'next':
15570                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15571                         switch(this.viewMode){
15572                                 case 0:
15573                                         this.viewDate = this.moveMonth(this.viewDate, dir);
15574                                         break;
15575                                 case 1:
15576                                 case 2:
15577                                         this.viewDate = this.moveYear(this.viewDate, dir);
15578                                         break;
15579                         }
15580                         this.fill();
15581                         break;
15582                     case 'today':
15583                         var date = new Date();
15584                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15585 //                        this.fill()
15586                         this.setValue(this.formatDate(this.date));
15587                         
15588                         this.hide();
15589                         break;
15590                 }
15591                 break;
15592             case 'span':
15593                 if (className.indexOf('disabled') < 0) {
15594                     this.viewDate.setUTCDate(1);
15595                     if (className.indexOf('month') > -1) {
15596                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15597                     } else {
15598                         var year = parseInt(html, 10) || 0;
15599                         this.viewDate.setUTCFullYear(year);
15600                         
15601                     }
15602                     
15603                     if(this.singleMode){
15604                         this.setValue(this.formatDate(this.viewDate));
15605                         this.hide();
15606                         return;
15607                     }
15608                     
15609                     this.showMode(-1);
15610                     this.fill();
15611                 }
15612                 break;
15613                 
15614             case 'td':
15615                 //Roo.log(className);
15616                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15617                     var day = parseInt(html, 10) || 1;
15618                     var year = this.viewDate.getUTCFullYear(),
15619                         month = this.viewDate.getUTCMonth();
15620
15621                     if (className.indexOf('old') > -1) {
15622                         if(month === 0 ){
15623                             month = 11;
15624                             year -= 1;
15625                         }else{
15626                             month -= 1;
15627                         }
15628                     } else if (className.indexOf('new') > -1) {
15629                         if (month == 11) {
15630                             month = 0;
15631                             year += 1;
15632                         } else {
15633                             month += 1;
15634                         }
15635                     }
15636                     //Roo.log([year,month,day]);
15637                     this.date = this.UTCDate(year, month, day,0,0,0,0);
15638                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15639 //                    this.fill();
15640                     //Roo.log(this.formatDate(this.date));
15641                     this.setValue(this.formatDate(this.date));
15642                     this.hide();
15643                 }
15644                 break;
15645         }
15646     },
15647     
15648     setStartDate: function(startDate)
15649     {
15650         this.startDate = startDate || -Infinity;
15651         if (this.startDate !== -Infinity) {
15652             this.startDate = this.parseDate(this.startDate);
15653         }
15654         this.update();
15655         this.updateNavArrows();
15656     },
15657
15658     setEndDate: function(endDate)
15659     {
15660         this.endDate = endDate || Infinity;
15661         if (this.endDate !== Infinity) {
15662             this.endDate = this.parseDate(this.endDate);
15663         }
15664         this.update();
15665         this.updateNavArrows();
15666     },
15667     
15668     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
15669     {
15670         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
15671         if (typeof(this.daysOfWeekDisabled) !== 'object') {
15672             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
15673         }
15674         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
15675             return parseInt(d, 10);
15676         });
15677         this.update();
15678         this.updateNavArrows();
15679     },
15680     
15681     updateNavArrows: function() 
15682     {
15683         if(this.singleMode){
15684             return;
15685         }
15686         
15687         var d = new Date(this.viewDate),
15688         year = d.getUTCFullYear(),
15689         month = d.getUTCMonth();
15690         
15691         Roo.each(this.picker().select('.prev', true).elements, function(v){
15692             v.show();
15693             switch (this.viewMode) {
15694                 case 0:
15695
15696                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
15697                         v.hide();
15698                     }
15699                     break;
15700                 case 1:
15701                 case 2:
15702                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
15703                         v.hide();
15704                     }
15705                     break;
15706             }
15707         });
15708         
15709         Roo.each(this.picker().select('.next', true).elements, function(v){
15710             v.show();
15711             switch (this.viewMode) {
15712                 case 0:
15713
15714                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
15715                         v.hide();
15716                     }
15717                     break;
15718                 case 1:
15719                 case 2:
15720                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
15721                         v.hide();
15722                     }
15723                     break;
15724             }
15725         })
15726     },
15727     
15728     moveMonth: function(date, dir)
15729     {
15730         if (!dir) return date;
15731         var new_date = new Date(date.valueOf()),
15732         day = new_date.getUTCDate(),
15733         month = new_date.getUTCMonth(),
15734         mag = Math.abs(dir),
15735         new_month, test;
15736         dir = dir > 0 ? 1 : -1;
15737         if (mag == 1){
15738             test = dir == -1
15739             // If going back one month, make sure month is not current month
15740             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
15741             ? function(){
15742                 return new_date.getUTCMonth() == month;
15743             }
15744             // If going forward one month, make sure month is as expected
15745             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
15746             : function(){
15747                 return new_date.getUTCMonth() != new_month;
15748             };
15749             new_month = month + dir;
15750             new_date.setUTCMonth(new_month);
15751             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
15752             if (new_month < 0 || new_month > 11)
15753                 new_month = (new_month + 12) % 12;
15754         } else {
15755             // For magnitudes >1, move one month at a time...
15756             for (var i=0; i<mag; i++)
15757                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
15758                 new_date = this.moveMonth(new_date, dir);
15759             // ...then reset the day, keeping it in the new month
15760             new_month = new_date.getUTCMonth();
15761             new_date.setUTCDate(day);
15762             test = function(){
15763                 return new_month != new_date.getUTCMonth();
15764             };
15765         }
15766         // Common date-resetting loop -- if date is beyond end of month, make it
15767         // end of month
15768         while (test()){
15769             new_date.setUTCDate(--day);
15770             new_date.setUTCMonth(new_month);
15771         }
15772         return new_date;
15773     },
15774
15775     moveYear: function(date, dir)
15776     {
15777         return this.moveMonth(date, dir*12);
15778     },
15779
15780     dateWithinRange: function(date)
15781     {
15782         return date >= this.startDate && date <= this.endDate;
15783     },
15784
15785     
15786     remove: function() 
15787     {
15788         this.picker().remove();
15789     }
15790    
15791 });
15792
15793 Roo.apply(Roo.bootstrap.DateField,  {
15794     
15795     head : {
15796         tag: 'thead',
15797         cn: [
15798         {
15799             tag: 'tr',
15800             cn: [
15801             {
15802                 tag: 'th',
15803                 cls: 'prev',
15804                 html: '<i class="fa fa-arrow-left"/>'
15805             },
15806             {
15807                 tag: 'th',
15808                 cls: 'switch',
15809                 colspan: '5'
15810             },
15811             {
15812                 tag: 'th',
15813                 cls: 'next',
15814                 html: '<i class="fa fa-arrow-right"/>'
15815             }
15816
15817             ]
15818         }
15819         ]
15820     },
15821     
15822     content : {
15823         tag: 'tbody',
15824         cn: [
15825         {
15826             tag: 'tr',
15827             cn: [
15828             {
15829                 tag: 'td',
15830                 colspan: '7'
15831             }
15832             ]
15833         }
15834         ]
15835     },
15836     
15837     footer : {
15838         tag: 'tfoot',
15839         cn: [
15840         {
15841             tag: 'tr',
15842             cn: [
15843             {
15844                 tag: 'th',
15845                 colspan: '7',
15846                 cls: 'today'
15847             }
15848                     
15849             ]
15850         }
15851         ]
15852     },
15853     
15854     dates:{
15855         en: {
15856             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
15857             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
15858             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
15859             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15860             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
15861             today: "Today"
15862         }
15863     },
15864     
15865     modes: [
15866     {
15867         clsName: 'days',
15868         navFnc: 'Month',
15869         navStep: 1
15870     },
15871     {
15872         clsName: 'months',
15873         navFnc: 'FullYear',
15874         navStep: 1
15875     },
15876     {
15877         clsName: 'years',
15878         navFnc: 'FullYear',
15879         navStep: 10
15880     }]
15881 });
15882
15883 Roo.apply(Roo.bootstrap.DateField,  {
15884   
15885     template : {
15886         tag: 'div',
15887         cls: 'datepicker dropdown-menu roo-dynamic',
15888         cn: [
15889         {
15890             tag: 'div',
15891             cls: 'datepicker-days',
15892             cn: [
15893             {
15894                 tag: 'table',
15895                 cls: 'table-condensed',
15896                 cn:[
15897                 Roo.bootstrap.DateField.head,
15898                 {
15899                     tag: 'tbody'
15900                 },
15901                 Roo.bootstrap.DateField.footer
15902                 ]
15903             }
15904             ]
15905         },
15906         {
15907             tag: 'div',
15908             cls: 'datepicker-months',
15909             cn: [
15910             {
15911                 tag: 'table',
15912                 cls: 'table-condensed',
15913                 cn:[
15914                 Roo.bootstrap.DateField.head,
15915                 Roo.bootstrap.DateField.content,
15916                 Roo.bootstrap.DateField.footer
15917                 ]
15918             }
15919             ]
15920         },
15921         {
15922             tag: 'div',
15923             cls: 'datepicker-years',
15924             cn: [
15925             {
15926                 tag: 'table',
15927                 cls: 'table-condensed',
15928                 cn:[
15929                 Roo.bootstrap.DateField.head,
15930                 Roo.bootstrap.DateField.content,
15931                 Roo.bootstrap.DateField.footer
15932                 ]
15933             }
15934             ]
15935         }
15936         ]
15937     }
15938 });
15939
15940  
15941
15942  /*
15943  * - LGPL
15944  *
15945  * TimeField
15946  * 
15947  */
15948
15949 /**
15950  * @class Roo.bootstrap.TimeField
15951  * @extends Roo.bootstrap.Input
15952  * Bootstrap DateField class
15953  * 
15954  * 
15955  * @constructor
15956  * Create a new TimeField
15957  * @param {Object} config The config object
15958  */
15959
15960 Roo.bootstrap.TimeField = function(config){
15961     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
15962     this.addEvents({
15963             /**
15964              * @event show
15965              * Fires when this field show.
15966              * @param {Roo.bootstrap.DateField} thisthis
15967              * @param {Mixed} date The date value
15968              */
15969             show : true,
15970             /**
15971              * @event show
15972              * Fires when this field hide.
15973              * @param {Roo.bootstrap.DateField} this
15974              * @param {Mixed} date The date value
15975              */
15976             hide : true,
15977             /**
15978              * @event select
15979              * Fires when select a date.
15980              * @param {Roo.bootstrap.DateField} this
15981              * @param {Mixed} date The date value
15982              */
15983             select : true
15984         });
15985 };
15986
15987 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
15988     
15989     /**
15990      * @cfg {String} format
15991      * The default time format string which can be overriden for localization support.  The format must be
15992      * valid according to {@link Date#parseDate} (defaults to 'H:i').
15993      */
15994     format : "H:i",
15995        
15996     onRender: function(ct, position)
15997     {
15998         
15999         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16000                 
16001         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16002         
16003         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16004         
16005         this.pop = this.picker().select('>.datepicker-time',true).first();
16006         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16007         
16008         this.picker().on('mousedown', this.onMousedown, this);
16009         this.picker().on('click', this.onClick, this);
16010         
16011         this.picker().addClass('datepicker-dropdown');
16012     
16013         this.fillTime();
16014         this.update();
16015             
16016         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16017         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16018         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16019         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16020         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16021         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16022
16023     },
16024     
16025     fireKey: function(e){
16026         if (!this.picker().isVisible()){
16027             if (e.keyCode == 27) { // allow escape to hide and re-show picker
16028                 this.show();
16029             }
16030             return;
16031         }
16032
16033         e.preventDefault();
16034         
16035         switch(e.keyCode){
16036             case 27: // escape
16037                 this.hide();
16038                 break;
16039             case 37: // left
16040             case 39: // right
16041                 this.onTogglePeriod();
16042                 break;
16043             case 38: // up
16044                 this.onIncrementMinutes();
16045                 break;
16046             case 40: // down
16047                 this.onDecrementMinutes();
16048                 break;
16049             case 13: // enter
16050             case 9: // tab
16051                 this.setTime();
16052                 break;
16053         }
16054     },
16055     
16056     onClick: function(e) {
16057         e.stopPropagation();
16058         e.preventDefault();
16059     },
16060     
16061     picker : function()
16062     {
16063         return this.el.select('.datepicker', true).first();
16064     },
16065     
16066     fillTime: function()
16067     {    
16068         var time = this.pop.select('tbody', true).first();
16069         
16070         time.dom.innerHTML = '';
16071         
16072         time.createChild({
16073             tag: 'tr',
16074             cn: [
16075                 {
16076                     tag: 'td',
16077                     cn: [
16078                         {
16079                             tag: 'a',
16080                             href: '#',
16081                             cls: 'btn',
16082                             cn: [
16083                                 {
16084                                     tag: 'span',
16085                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
16086                                 }
16087                             ]
16088                         } 
16089                     ]
16090                 },
16091                 {
16092                     tag: 'td',
16093                     cls: 'separator'
16094                 },
16095                 {
16096                     tag: 'td',
16097                     cn: [
16098                         {
16099                             tag: 'a',
16100                             href: '#',
16101                             cls: 'btn',
16102                             cn: [
16103                                 {
16104                                     tag: 'span',
16105                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
16106                                 }
16107                             ]
16108                         }
16109                     ]
16110                 },
16111                 {
16112                     tag: 'td',
16113                     cls: 'separator'
16114                 }
16115             ]
16116         });
16117         
16118         time.createChild({
16119             tag: 'tr',
16120             cn: [
16121                 {
16122                     tag: 'td',
16123                     cn: [
16124                         {
16125                             tag: 'span',
16126                             cls: 'timepicker-hour',
16127                             html: '00'
16128                         }  
16129                     ]
16130                 },
16131                 {
16132                     tag: 'td',
16133                     cls: 'separator',
16134                     html: ':'
16135                 },
16136                 {
16137                     tag: 'td',
16138                     cn: [
16139                         {
16140                             tag: 'span',
16141                             cls: 'timepicker-minute',
16142                             html: '00'
16143                         }  
16144                     ]
16145                 },
16146                 {
16147                     tag: 'td',
16148                     cls: 'separator'
16149                 },
16150                 {
16151                     tag: 'td',
16152                     cn: [
16153                         {
16154                             tag: 'button',
16155                             type: 'button',
16156                             cls: 'btn btn-primary period',
16157                             html: 'AM'
16158                             
16159                         }
16160                     ]
16161                 }
16162             ]
16163         });
16164         
16165         time.createChild({
16166             tag: 'tr',
16167             cn: [
16168                 {
16169                     tag: 'td',
16170                     cn: [
16171                         {
16172                             tag: 'a',
16173                             href: '#',
16174                             cls: 'btn',
16175                             cn: [
16176                                 {
16177                                     tag: 'span',
16178                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
16179                                 }
16180                             ]
16181                         }
16182                     ]
16183                 },
16184                 {
16185                     tag: 'td',
16186                     cls: 'separator'
16187                 },
16188                 {
16189                     tag: 'td',
16190                     cn: [
16191                         {
16192                             tag: 'a',
16193                             href: '#',
16194                             cls: 'btn',
16195                             cn: [
16196                                 {
16197                                     tag: 'span',
16198                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
16199                                 }
16200                             ]
16201                         }
16202                     ]
16203                 },
16204                 {
16205                     tag: 'td',
16206                     cls: 'separator'
16207                 }
16208             ]
16209         });
16210         
16211     },
16212     
16213     update: function()
16214     {
16215         
16216         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16217         
16218         this.fill();
16219     },
16220     
16221     fill: function() 
16222     {
16223         var hours = this.time.getHours();
16224         var minutes = this.time.getMinutes();
16225         var period = 'AM';
16226         
16227         if(hours > 11){
16228             period = 'PM';
16229         }
16230         
16231         if(hours == 0){
16232             hours = 12;
16233         }
16234         
16235         
16236         if(hours > 12){
16237             hours = hours - 12;
16238         }
16239         
16240         if(hours < 10){
16241             hours = '0' + hours;
16242         }
16243         
16244         if(minutes < 10){
16245             minutes = '0' + minutes;
16246         }
16247         
16248         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16249         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16250         this.pop.select('button', true).first().dom.innerHTML = period;
16251         
16252     },
16253     
16254     place: function()
16255     {   
16256         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16257         
16258         var cls = ['bottom'];
16259         
16260         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16261             cls.pop();
16262             cls.push('top');
16263         }
16264         
16265         cls.push('right');
16266         
16267         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16268             cls.pop();
16269             cls.push('left');
16270         }
16271         
16272         this.picker().addClass(cls.join('-'));
16273         
16274         var _this = this;
16275         
16276         Roo.each(cls, function(c){
16277             if(c == 'bottom'){
16278                 _this.picker().setTop(_this.inputEl().getHeight());
16279                 return;
16280             }
16281             if(c == 'top'){
16282                 _this.picker().setTop(0 - _this.picker().getHeight());
16283                 return;
16284             }
16285             
16286             if(c == 'left'){
16287                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16288                 return;
16289             }
16290             if(c == 'right'){
16291                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16292                 return;
16293             }
16294         });
16295         
16296     },
16297   
16298     onFocus : function()
16299     {
16300         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16301         this.show();
16302     },
16303     
16304     onBlur : function()
16305     {
16306         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16307         this.hide();
16308     },
16309     
16310     show : function()
16311     {
16312         this.picker().show();
16313         this.pop.show();
16314         this.update();
16315         this.place();
16316         
16317         this.fireEvent('show', this, this.date);
16318     },
16319     
16320     hide : function()
16321     {
16322         this.picker().hide();
16323         this.pop.hide();
16324         
16325         this.fireEvent('hide', this, this.date);
16326     },
16327     
16328     setTime : function()
16329     {
16330         this.hide();
16331         this.setValue(this.time.format(this.format));
16332         
16333         this.fireEvent('select', this, this.date);
16334         
16335         
16336     },
16337     
16338     onMousedown: function(e){
16339         e.stopPropagation();
16340         e.preventDefault();
16341     },
16342     
16343     onIncrementHours: function()
16344     {
16345         Roo.log('onIncrementHours');
16346         this.time = this.time.add(Date.HOUR, 1);
16347         this.update();
16348         
16349     },
16350     
16351     onDecrementHours: function()
16352     {
16353         Roo.log('onDecrementHours');
16354         this.time = this.time.add(Date.HOUR, -1);
16355         this.update();
16356     },
16357     
16358     onIncrementMinutes: function()
16359     {
16360         Roo.log('onIncrementMinutes');
16361         this.time = this.time.add(Date.MINUTE, 1);
16362         this.update();
16363     },
16364     
16365     onDecrementMinutes: function()
16366     {
16367         Roo.log('onDecrementMinutes');
16368         this.time = this.time.add(Date.MINUTE, -1);
16369         this.update();
16370     },
16371     
16372     onTogglePeriod: function()
16373     {
16374         Roo.log('onTogglePeriod');
16375         this.time = this.time.add(Date.HOUR, 12);
16376         this.update();
16377     }
16378     
16379    
16380 });
16381
16382 Roo.apply(Roo.bootstrap.TimeField,  {
16383     
16384     content : {
16385         tag: 'tbody',
16386         cn: [
16387             {
16388                 tag: 'tr',
16389                 cn: [
16390                 {
16391                     tag: 'td',
16392                     colspan: '7'
16393                 }
16394                 ]
16395             }
16396         ]
16397     },
16398     
16399     footer : {
16400         tag: 'tfoot',
16401         cn: [
16402             {
16403                 tag: 'tr',
16404                 cn: [
16405                 {
16406                     tag: 'th',
16407                     colspan: '7',
16408                     cls: '',
16409                     cn: [
16410                         {
16411                             tag: 'button',
16412                             cls: 'btn btn-info ok',
16413                             html: 'OK'
16414                         }
16415                     ]
16416                 }
16417
16418                 ]
16419             }
16420         ]
16421     }
16422 });
16423
16424 Roo.apply(Roo.bootstrap.TimeField,  {
16425   
16426     template : {
16427         tag: 'div',
16428         cls: 'datepicker dropdown-menu',
16429         cn: [
16430             {
16431                 tag: 'div',
16432                 cls: 'datepicker-time',
16433                 cn: [
16434                 {
16435                     tag: 'table',
16436                     cls: 'table-condensed',
16437                     cn:[
16438                     Roo.bootstrap.TimeField.content,
16439                     Roo.bootstrap.TimeField.footer
16440                     ]
16441                 }
16442                 ]
16443             }
16444         ]
16445     }
16446 });
16447
16448  
16449
16450  /*
16451  * - LGPL
16452  *
16453  * MonthField
16454  * 
16455  */
16456
16457 /**
16458  * @class Roo.bootstrap.MonthField
16459  * @extends Roo.bootstrap.Input
16460  * Bootstrap MonthField class
16461  * 
16462  * @cfg {String} language default en
16463  * 
16464  * @constructor
16465  * Create a new MonthField
16466  * @param {Object} config The config object
16467  */
16468
16469 Roo.bootstrap.MonthField = function(config){
16470     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16471     
16472     this.addEvents({
16473         /**
16474          * @event show
16475          * Fires when this field show.
16476          * @param {Roo.bootstrap.MonthField} this
16477          * @param {Mixed} date The date value
16478          */
16479         show : true,
16480         /**
16481          * @event show
16482          * Fires when this field hide.
16483          * @param {Roo.bootstrap.MonthField} this
16484          * @param {Mixed} date The date value
16485          */
16486         hide : true,
16487         /**
16488          * @event select
16489          * Fires when select a date.
16490          * @param {Roo.bootstrap.MonthField} this
16491          * @param {String} oldvalue The old value
16492          * @param {String} newvalue The new value
16493          */
16494         select : true
16495     });
16496 };
16497
16498 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
16499     
16500     onRender: function(ct, position)
16501     {
16502         
16503         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16504         
16505         this.language = this.language || 'en';
16506         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16507         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16508         
16509         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16510         this.isInline = false;
16511         this.isInput = true;
16512         this.component = this.el.select('.add-on', true).first() || false;
16513         this.component = (this.component && this.component.length === 0) ? false : this.component;
16514         this.hasInput = this.component && this.inputEL().length;
16515         
16516         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16517         
16518         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16519         
16520         this.picker().on('mousedown', this.onMousedown, this);
16521         this.picker().on('click', this.onClick, this);
16522         
16523         this.picker().addClass('datepicker-dropdown');
16524         
16525         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16526             v.setStyle('width', '189px');
16527         });
16528         
16529         this.fillMonths();
16530         
16531         this.update();
16532         
16533         if(this.isInline) {
16534             this.show();
16535         }
16536         
16537     },
16538     
16539     setValue: function(v, suppressEvent)
16540     {   
16541         var o = this.getValue();
16542         
16543         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16544         
16545         this.update();
16546
16547         if(suppressEvent !== true){
16548             this.fireEvent('select', this, o, v);
16549         }
16550         
16551     },
16552     
16553     getValue: function()
16554     {
16555         return this.value;
16556     },
16557     
16558     onClick: function(e) 
16559     {
16560         e.stopPropagation();
16561         e.preventDefault();
16562         
16563         var target = e.getTarget();
16564         
16565         if(target.nodeName.toLowerCase() === 'i'){
16566             target = Roo.get(target).dom.parentNode;
16567         }
16568         
16569         var nodeName = target.nodeName;
16570         var className = target.className;
16571         var html = target.innerHTML;
16572         
16573         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16574             return;
16575         }
16576         
16577         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16578         
16579         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16580         
16581         this.hide();
16582                         
16583     },
16584     
16585     picker : function()
16586     {
16587         return this.pickerEl;
16588     },
16589     
16590     fillMonths: function()
16591     {    
16592         var i = 0;
16593         var months = this.picker().select('>.datepicker-months td', true).first();
16594         
16595         months.dom.innerHTML = '';
16596         
16597         while (i < 12) {
16598             var month = {
16599                 tag: 'span',
16600                 cls: 'month',
16601                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16602             }
16603             
16604             months.createChild(month);
16605         }
16606         
16607     },
16608     
16609     update: function()
16610     {
16611         var _this = this;
16612         
16613         if(typeof(this.vIndex) == 'undefined' && this.value.length){
16614             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16615         }
16616         
16617         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16618             e.removeClass('active');
16619             
16620             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16621                 e.addClass('active');
16622             }
16623         })
16624     },
16625     
16626     place: function()
16627     {
16628         if(this.isInline) return;
16629         
16630         this.picker().removeClass(['bottom', 'top']);
16631         
16632         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16633             /*
16634              * place to the top of element!
16635              *
16636              */
16637             
16638             this.picker().addClass('top');
16639             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16640             
16641             return;
16642         }
16643         
16644         this.picker().addClass('bottom');
16645         
16646         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16647     },
16648     
16649     onFocus : function()
16650     {
16651         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
16652         this.show();
16653     },
16654     
16655     onBlur : function()
16656     {
16657         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
16658         
16659         var d = this.inputEl().getValue();
16660         
16661         this.setValue(d);
16662                 
16663         this.hide();
16664     },
16665     
16666     show : function()
16667     {
16668         this.picker().show();
16669         this.picker().select('>.datepicker-months', true).first().show();
16670         this.update();
16671         this.place();
16672         
16673         this.fireEvent('show', this, this.date);
16674     },
16675     
16676     hide : function()
16677     {
16678         if(this.isInline) return;
16679         this.picker().hide();
16680         this.fireEvent('hide', this, this.date);
16681         
16682     },
16683     
16684     onMousedown: function(e)
16685     {
16686         e.stopPropagation();
16687         e.preventDefault();
16688     },
16689     
16690     keyup: function(e)
16691     {
16692         Roo.bootstrap.MonthField.superclass.keyup.call(this);
16693         this.update();
16694     },
16695
16696     fireKey: function(e)
16697     {
16698         if (!this.picker().isVisible()){
16699             if (e.keyCode == 27) // allow escape to hide and re-show picker
16700                 this.show();
16701             return;
16702         }
16703         
16704         var dir;
16705         
16706         switch(e.keyCode){
16707             case 27: // escape
16708                 this.hide();
16709                 e.preventDefault();
16710                 break;
16711             case 37: // left
16712             case 39: // right
16713                 dir = e.keyCode == 37 ? -1 : 1;
16714                 
16715                 this.vIndex = this.vIndex + dir;
16716                 
16717                 if(this.vIndex < 0){
16718                     this.vIndex = 0;
16719                 }
16720                 
16721                 if(this.vIndex > 11){
16722                     this.vIndex = 11;
16723                 }
16724                 
16725                 if(isNaN(this.vIndex)){
16726                     this.vIndex = 0;
16727                 }
16728                 
16729                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16730                 
16731                 break;
16732             case 38: // up
16733             case 40: // down
16734                 
16735                 dir = e.keyCode == 38 ? -1 : 1;
16736                 
16737                 this.vIndex = this.vIndex + dir * 4;
16738                 
16739                 if(this.vIndex < 0){
16740                     this.vIndex = 0;
16741                 }
16742                 
16743                 if(this.vIndex > 11){
16744                     this.vIndex = 11;
16745                 }
16746                 
16747                 if(isNaN(this.vIndex)){
16748                     this.vIndex = 0;
16749                 }
16750                 
16751                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16752                 break;
16753                 
16754             case 13: // enter
16755                 
16756                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16757                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16758                 }
16759                 
16760                 this.hide();
16761                 e.preventDefault();
16762                 break;
16763             case 9: // tab
16764                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
16765                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16766                 }
16767                 this.hide();
16768                 break;
16769             case 16: // shift
16770             case 17: // ctrl
16771             case 18: // alt
16772                 break;
16773             default :
16774                 this.hide();
16775                 
16776         }
16777     },
16778     
16779     remove: function() 
16780     {
16781         this.picker().remove();
16782     }
16783    
16784 });
16785
16786 Roo.apply(Roo.bootstrap.MonthField,  {
16787     
16788     content : {
16789         tag: 'tbody',
16790         cn: [
16791         {
16792             tag: 'tr',
16793             cn: [
16794             {
16795                 tag: 'td',
16796                 colspan: '7'
16797             }
16798             ]
16799         }
16800         ]
16801     },
16802     
16803     dates:{
16804         en: {
16805             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16806             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
16807         }
16808     }
16809 });
16810
16811 Roo.apply(Roo.bootstrap.MonthField,  {
16812   
16813     template : {
16814         tag: 'div',
16815         cls: 'datepicker dropdown-menu roo-dynamic',
16816         cn: [
16817             {
16818                 tag: 'div',
16819                 cls: 'datepicker-months',
16820                 cn: [
16821                 {
16822                     tag: 'table',
16823                     cls: 'table-condensed',
16824                     cn:[
16825                         Roo.bootstrap.DateField.content
16826                     ]
16827                 }
16828                 ]
16829             }
16830         ]
16831     }
16832 });
16833
16834  
16835
16836  
16837  /*
16838  * - LGPL
16839  *
16840  * CheckBox
16841  * 
16842  */
16843
16844 /**
16845  * @class Roo.bootstrap.CheckBox
16846  * @extends Roo.bootstrap.Input
16847  * Bootstrap CheckBox class
16848  * 
16849  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
16850  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
16851  * @cfg {String} boxLabel The text that appears beside the checkbox
16852  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
16853  * @cfg {Boolean} checked initnal the element
16854  * @cfg {Boolean} inline inline the element (default false)
16855  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
16856  * 
16857  * @constructor
16858  * Create a new CheckBox
16859  * @param {Object} config The config object
16860  */
16861
16862 Roo.bootstrap.CheckBox = function(config){
16863     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
16864    
16865     this.addEvents({
16866         /**
16867         * @event check
16868         * Fires when the element is checked or unchecked.
16869         * @param {Roo.bootstrap.CheckBox} this This input
16870         * @param {Boolean} checked The new checked value
16871         */
16872        check : true
16873     });
16874     
16875 };
16876
16877 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
16878   
16879     inputType: 'checkbox',
16880     inputValue: 1,
16881     valueOff: 0,
16882     boxLabel: false,
16883     checked: false,
16884     weight : false,
16885     inline: false,
16886     
16887     getAutoCreate : function()
16888     {
16889         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
16890         
16891         var id = Roo.id();
16892         
16893         var cfg = {};
16894         
16895         cfg.cls = 'form-group ' + this.inputType; //input-group
16896         
16897         if(this.inline){
16898             cfg.cls += ' ' + this.inputType + '-inline';
16899         }
16900         
16901         var input =  {
16902             tag: 'input',
16903             id : id,
16904             type : this.inputType,
16905             value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
16906             cls : 'roo-' + this.inputType, //'form-box',
16907             placeholder : this.placeholder || ''
16908             
16909         };
16910         
16911         if (this.weight) { // Validity check?
16912             cfg.cls += " " + this.inputType + "-" + this.weight;
16913         }
16914         
16915         if (this.disabled) {
16916             input.disabled=true;
16917         }
16918         
16919         if(this.checked){
16920             input.checked = this.checked;
16921         }
16922         
16923         if (this.name) {
16924             input.name = this.name;
16925         }
16926         
16927         if (this.size) {
16928             input.cls += ' input-' + this.size;
16929         }
16930         
16931         var settings=this;
16932         
16933         ['xs','sm','md','lg'].map(function(size){
16934             if (settings[size]) {
16935                 cfg.cls += ' col-' + size + '-' + settings[size];
16936             }
16937         });
16938         
16939         var inputblock = input;
16940          
16941         if (this.before || this.after) {
16942             
16943             inputblock = {
16944                 cls : 'input-group',
16945                 cn :  [] 
16946             };
16947             
16948             if (this.before) {
16949                 inputblock.cn.push({
16950                     tag :'span',
16951                     cls : 'input-group-addon',
16952                     html : this.before
16953                 });
16954             }
16955             
16956             inputblock.cn.push(input);
16957             
16958             if (this.after) {
16959                 inputblock.cn.push({
16960                     tag :'span',
16961                     cls : 'input-group-addon',
16962                     html : this.after
16963                 });
16964             }
16965             
16966         }
16967         
16968         if (align ==='left' && this.fieldLabel.length) {
16969                 Roo.log("left and has label");
16970                 cfg.cn = [
16971                     
16972                     {
16973                         tag: 'label',
16974                         'for' :  id,
16975                         cls : 'control-label col-md-' + this.labelWidth,
16976                         html : this.fieldLabel
16977                         
16978                     },
16979                     {
16980                         cls : "col-md-" + (12 - this.labelWidth), 
16981                         cn: [
16982                             inputblock
16983                         ]
16984                     }
16985                     
16986                 ];
16987         } else if ( this.fieldLabel.length) {
16988                 Roo.log(" label");
16989                 cfg.cn = [
16990                    
16991                     {
16992                         tag: this.boxLabel ? 'span' : 'label',
16993                         'for': id,
16994                         cls: 'control-label box-input-label',
16995                         //cls : 'input-group-addon',
16996                         html : this.fieldLabel
16997                         
16998                     },
16999                     
17000                     inputblock
17001                     
17002                 ];
17003
17004         } else {
17005             
17006                 Roo.log(" no label && no align");
17007                 cfg.cn = [  inputblock ] ;
17008                 
17009                 
17010         }
17011         if(this.boxLabel){
17012              var boxLabelCfg = {
17013                 tag: 'label',
17014                 //'for': id, // box label is handled by onclick - so no for...
17015                 cls: 'box-label',
17016                 html: this.boxLabel
17017             }
17018             
17019             if(this.tooltip){
17020                 boxLabelCfg.tooltip = this.tooltip;
17021             }
17022              
17023             cfg.cn.push(boxLabelCfg);
17024         }
17025         
17026         
17027        
17028         return cfg;
17029         
17030     },
17031     
17032     /**
17033      * return the real input element.
17034      */
17035     inputEl: function ()
17036     {
17037         return this.el.select('input.roo-' + this.inputType,true).first();
17038     },
17039     
17040     labelEl: function()
17041     {
17042         return this.el.select('label.control-label',true).first();
17043     },
17044     /* depricated... */
17045     
17046     label: function()
17047     {
17048         return this.labelEl();
17049     },
17050     
17051     initEvents : function()
17052     {
17053 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17054         
17055         this.inputEl().on('click', this.onClick,  this);
17056         
17057         if (this.boxLabel) { 
17058             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
17059         }
17060         
17061         this.startValue = this.getValue();
17062         
17063         if(this.groupId){
17064             Roo.bootstrap.CheckBox.register(this);
17065         }
17066     },
17067     
17068     onClick : function()
17069     {   
17070         this.setChecked(!this.checked);
17071     },
17072     
17073     setChecked : function(state,suppressEvent)
17074     {
17075         this.startValue = this.getValue();
17076         
17077         if(this.inputType == 'radio'){
17078             
17079             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17080                 e.dom.checked = false;
17081             });
17082             
17083             this.inputEl().dom.checked = true;
17084             
17085             this.inputEl().dom.value = this.inputValue;
17086             
17087             if(suppressEvent !== true){
17088                 this.fireEvent('check', this, true);
17089             }
17090             
17091             this.validate();
17092             
17093             return;
17094         }
17095         
17096         this.checked = state;
17097         
17098         this.inputEl().dom.checked = state;
17099         
17100         this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17101         
17102         if(suppressEvent !== true){
17103             this.fireEvent('check', this, state);
17104         }
17105         
17106         this.validate();
17107     },
17108     
17109     getValue : function()
17110     {
17111         if(this.inputType == 'radio'){
17112             return this.getGroupValue();
17113         }
17114         
17115         return this.inputEl().getValue();
17116         
17117     },
17118     
17119     getGroupValue : function()
17120     {
17121         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17122             return '';
17123         }
17124         
17125         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17126     },
17127     
17128     setValue : function(v,suppressEvent)
17129     {
17130         if(this.inputType == 'radio'){
17131             this.setGroupValue(v, suppressEvent);
17132             return;
17133         }
17134         
17135         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17136         
17137         this.validate();
17138     },
17139     
17140     setGroupValue : function(v, suppressEvent)
17141     {
17142         this.startValue = this.getValue();
17143         
17144         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17145             e.dom.checked = false;
17146             
17147             if(e.dom.value == v){
17148                 e.dom.checked = true;
17149             }
17150         });
17151         
17152         if(suppressEvent !== true){
17153             this.fireEvent('check', this, true);
17154         }
17155
17156         this.validate();
17157         
17158         return;
17159     },
17160     
17161     validate : function()
17162     {
17163         if(
17164                 this.disabled || 
17165                 (this.inputType == 'radio' && this.validateRadio()) ||
17166                 (this.inputType == 'checkbox' && this.validateCheckbox())
17167         ){
17168             this.markValid();
17169             return true;
17170         }
17171         
17172         this.markInvalid();
17173         return false;
17174     },
17175     
17176     validateRadio : function()
17177     {
17178         var valid = false;
17179         
17180         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17181             if(!e.dom.checked){
17182                 return;
17183             }
17184             
17185             valid = true;
17186             
17187             return false;
17188         });
17189         
17190         return valid;
17191     },
17192     
17193     validateCheckbox : function()
17194     {
17195         if(!this.groupId){
17196             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17197         }
17198         
17199         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17200         
17201         if(!group){
17202             return false;
17203         }
17204         
17205         var r = false;
17206         
17207         for(var i in group){
17208             if(r){
17209                 break;
17210             }
17211             
17212             r = (group[i].getValue() == group[i].inputValue) ? true : false;
17213         }
17214         
17215         return r;
17216     },
17217     
17218     /**
17219      * Mark this field as valid
17220      */
17221     markValid : function()
17222     {
17223         if(this.allowBlank){
17224             return;
17225         }
17226         
17227         var _this = this;
17228         
17229         this.fireEvent('valid', this);
17230         
17231         if(this.inputType == 'radio'){
17232             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17233                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17234                 e.findParent('.form-group', false, true).addClass(_this.validClass);
17235             });
17236             
17237             return;
17238         }
17239         
17240         if(!this.groupId){
17241             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17242             this.el.findParent('.form-group', false, true).addClass(this.validClass);
17243             return;
17244         }
17245         
17246         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17247             
17248         if(!group){
17249             return;
17250         }
17251         
17252         for(var i in group){
17253             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17254             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17255         }
17256     },
17257     
17258      /**
17259      * Mark this field as invalid
17260      * @param {String} msg The validation message
17261      */
17262     markInvalid : function(msg)
17263     {
17264         if(this.allowBlank){
17265             return;
17266         }
17267         
17268         var _this = this;
17269         
17270         this.fireEvent('invalid', this, msg);
17271         
17272         if(this.inputType == 'radio'){
17273             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17274                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17275                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17276             });
17277             
17278             return;
17279         }
17280         
17281         if(!this.groupId){
17282             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17283             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17284             return;
17285         }
17286         
17287         var group = Roo.bootstrap.CheckBox.get(this.groupId);
17288             
17289         if(!group){
17290             return;
17291         }
17292         
17293         for(var i in group){
17294             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17295             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17296         }
17297         
17298     }
17299     
17300 });
17301
17302 Roo.apply(Roo.bootstrap.CheckBox, {
17303     
17304     groups: {},
17305     
17306      /**
17307     * register a CheckBox Group
17308     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17309     */
17310     register : function(checkbox)
17311     {
17312         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17313             this.groups[checkbox.groupId] = {};
17314         }
17315         
17316         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17317             return;
17318         }
17319         
17320         this.groups[checkbox.groupId][checkbox.name] = checkbox;
17321         
17322     },
17323     /**
17324     * fetch a CheckBox Group based on the group ID
17325     * @param {string} the group ID
17326     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17327     */
17328     get: function(groupId) {
17329         if (typeof(this.groups[groupId]) == 'undefined') {
17330             return false;
17331         }
17332         
17333         return this.groups[groupId] ;
17334     }
17335     
17336     
17337 });
17338 /*
17339  * - LGPL
17340  *
17341  * Radio
17342  *
17343  *
17344  * not inline
17345  *<div class="radio">
17346   <label>
17347     <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17348     Option one is this and that&mdash;be sure to include why it's great
17349   </label>
17350 </div>
17351  *
17352  *
17353  *inline
17354  *<span>
17355  *<label class="radio-inline">fieldLabel</label>
17356  *<label class="radio-inline">
17357   <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17358 </label>
17359 <span>
17360  * 
17361  * 
17362  */
17363
17364 /**
17365  * @class Roo.bootstrap.Radio
17366  * @extends Roo.bootstrap.CheckBox
17367  * Bootstrap Radio class
17368
17369  * @constructor
17370  * Create a new Radio
17371  * @param {Object} config The config object
17372  */
17373
17374 Roo.bootstrap.Radio = function(config){
17375     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17376    
17377 };
17378
17379 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox,  {
17380     
17381     inputType: 'radio',
17382     inputValue: '',
17383     valueOff: '',
17384     
17385     getAutoCreate : function()
17386     {
17387         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17388         align = align || 'left'; // default...
17389         
17390         
17391         
17392         var id = Roo.id();
17393         
17394         var cfg = {
17395                 tag : this.inline ? 'span' : 'div',
17396                 cls : '',
17397                 cn : []
17398         };
17399         
17400         var inline = this.inline ? ' radio-inline' : '';
17401         
17402         var lbl = {
17403                 tag: 'label' ,
17404                 // does not need for, as we wrap the input with it..
17405                 'for' : id,
17406                 cls : 'control-label box-label' + inline,
17407                 cn : []
17408         };
17409         var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17410         
17411         var fieldLabel = {
17412             tag: 'label' ,
17413             //cls : 'control-label' + inline,
17414             html : this.fieldLabel,
17415             style : 'width:' +  labelWidth  + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17416         };
17417         
17418  
17419         
17420         
17421         var input =  {
17422             tag: 'input',
17423             id : id,
17424             type : this.inputType,
17425             //value : (!this.checked) ? this.valueOff : this.inputValue,
17426             value : this.inputValue,
17427             cls : 'roo-radio',
17428             placeholder : this.placeholder || '' // ?? needed????
17429             
17430         };
17431         if (this.weight) { // Validity check?
17432             input.cls += " radio-" + this.weight;
17433         }
17434         if (this.disabled) {
17435             input.disabled=true;
17436         }
17437         
17438         if(this.checked){
17439             input.checked = this.checked;
17440         }
17441         
17442         if (this.name) {
17443             input.name = this.name;
17444         }
17445         
17446         if (this.size) {
17447             input.cls += ' input-' + this.size;
17448         }
17449         
17450         //?? can span's inline have a width??
17451         
17452         var settings=this;
17453         ['xs','sm','md','lg'].map(function(size){
17454             if (settings[size]) {
17455                 cfg.cls += ' col-' + size + '-' + settings[size];
17456             }
17457         });
17458         
17459         var inputblock = input;
17460         
17461         if (this.before || this.after) {
17462             
17463             inputblock = {
17464                 cls : 'input-group',
17465                 tag : 'span',
17466                 cn :  [] 
17467             };
17468             if (this.before) {
17469                 inputblock.cn.push({
17470                     tag :'span',
17471                     cls : 'input-group-addon',
17472                     html : this.before
17473                 });
17474             }
17475             inputblock.cn.push(input);
17476             if (this.after) {
17477                 inputblock.cn.push({
17478                     tag :'span',
17479                     cls : 'input-group-addon',
17480                     html : this.after
17481                 });
17482             }
17483             
17484         };
17485         
17486         
17487         if (this.fieldLabel && this.fieldLabel.length) {
17488             cfg.cn.push(fieldLabel);
17489         }
17490        
17491         // normal bootstrap puts the input inside the label.
17492         // however with our styled version - it has to go after the input.
17493        
17494         //lbl.cn.push(inputblock);
17495         
17496         var lblwrap =  {
17497             tag: 'span',
17498             cls: 'radio' + inline,
17499             cn: [
17500                 inputblock,
17501                 lbl
17502             ]
17503         };
17504         
17505         cfg.cn.push( lblwrap);
17506         
17507         if(this.boxLabel){
17508             lbl.cn.push({
17509                 tag: 'span',
17510                 html: this.boxLabel
17511             })
17512         }
17513          
17514         
17515         return cfg;
17516         
17517     },
17518     
17519     initEvents : function()
17520     {
17521 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17522         
17523         this.inputEl().on('click', this.onClick,  this);
17524         if (this.boxLabel) {
17525             Roo.log('find label')
17526             this.el.select('span.radio label span',true).first().on('click', this.onClick,  this);
17527         }
17528         
17529     },
17530     
17531     inputEl: function ()
17532     {
17533         return this.el.select('input.roo-radio',true).first();
17534     },
17535     onClick : function()
17536     {   
17537         Roo.log("click");
17538         this.setChecked(true);
17539     },
17540     
17541     setChecked : function(state,suppressEvent)
17542     {
17543         if(state){
17544             Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17545                 v.dom.checked = false;
17546             });
17547         }
17548         Roo.log(this.inputEl().dom);
17549         this.checked = state;
17550         this.inputEl().dom.checked = state;
17551         
17552         if(suppressEvent !== true){
17553             this.fireEvent('check', this, state);
17554         }
17555         
17556         //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17557         
17558     },
17559     
17560     getGroupValue : function()
17561     {
17562         var value = '';
17563         Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17564             if(v.dom.checked == true){
17565                 value = v.dom.value;
17566             }
17567         });
17568         
17569         return value;
17570     },
17571     
17572     /**
17573      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
17574      * @return {Mixed} value The field value
17575      */
17576     getValue : function(){
17577         return this.getGroupValue();
17578     }
17579     
17580 });
17581
17582  
17583 //<script type="text/javascript">
17584
17585 /*
17586  * Based  Ext JS Library 1.1.1
17587  * Copyright(c) 2006-2007, Ext JS, LLC.
17588  * LGPL
17589  *
17590  */
17591  
17592 /**
17593  * @class Roo.HtmlEditorCore
17594  * @extends Roo.Component
17595  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17596  *
17597  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17598  */
17599
17600 Roo.HtmlEditorCore = function(config){
17601     
17602     
17603     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17604     
17605     
17606     this.addEvents({
17607         /**
17608          * @event initialize
17609          * Fires when the editor is fully initialized (including the iframe)
17610          * @param {Roo.HtmlEditorCore} this
17611          */
17612         initialize: true,
17613         /**
17614          * @event activate
17615          * Fires when the editor is first receives the focus. Any insertion must wait
17616          * until after this event.
17617          * @param {Roo.HtmlEditorCore} this
17618          */
17619         activate: true,
17620          /**
17621          * @event beforesync
17622          * Fires before the textarea is updated with content from the editor iframe. Return false
17623          * to cancel the sync.
17624          * @param {Roo.HtmlEditorCore} this
17625          * @param {String} html
17626          */
17627         beforesync: true,
17628          /**
17629          * @event beforepush
17630          * Fires before the iframe editor is updated with content from the textarea. Return false
17631          * to cancel the push.
17632          * @param {Roo.HtmlEditorCore} this
17633          * @param {String} html
17634          */
17635         beforepush: true,
17636          /**
17637          * @event sync
17638          * Fires when the textarea is updated with content from the editor iframe.
17639          * @param {Roo.HtmlEditorCore} this
17640          * @param {String} html
17641          */
17642         sync: true,
17643          /**
17644          * @event push
17645          * Fires when the iframe editor is updated with content from the textarea.
17646          * @param {Roo.HtmlEditorCore} this
17647          * @param {String} html
17648          */
17649         push: true,
17650         
17651         /**
17652          * @event editorevent
17653          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
17654          * @param {Roo.HtmlEditorCore} this
17655          */
17656         editorevent: true
17657         
17658     });
17659     
17660     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
17661     
17662     // defaults : white / black...
17663     this.applyBlacklists();
17664     
17665     
17666     
17667 };
17668
17669
17670 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
17671
17672
17673      /**
17674      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
17675      */
17676     
17677     owner : false,
17678     
17679      /**
17680      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
17681      *                        Roo.resizable.
17682      */
17683     resizable : false,
17684      /**
17685      * @cfg {Number} height (in pixels)
17686      */   
17687     height: 300,
17688    /**
17689      * @cfg {Number} width (in pixels)
17690      */   
17691     width: 500,
17692     
17693     /**
17694      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
17695      * 
17696      */
17697     stylesheets: false,
17698     
17699     // id of frame..
17700     frameId: false,
17701     
17702     // private properties
17703     validationEvent : false,
17704     deferHeight: true,
17705     initialized : false,
17706     activated : false,
17707     sourceEditMode : false,
17708     onFocus : Roo.emptyFn,
17709     iframePad:3,
17710     hideMode:'offsets',
17711     
17712     clearUp: true,
17713     
17714     // blacklist + whitelisted elements..
17715     black: false,
17716     white: false,
17717      
17718     
17719
17720     /**
17721      * Protected method that will not generally be called directly. It
17722      * is called when the editor initializes the iframe with HTML contents. Override this method if you
17723      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
17724      */
17725     getDocMarkup : function(){
17726         // body styles..
17727         var st = '';
17728         
17729         // inherit styels from page...?? 
17730         if (this.stylesheets === false) {
17731             
17732             Roo.get(document.head).select('style').each(function(node) {
17733                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17734             });
17735             
17736             Roo.get(document.head).select('link').each(function(node) { 
17737                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
17738             });
17739             
17740         } else if (!this.stylesheets.length) {
17741                 // simple..
17742                 st = '<style type="text/css">' +
17743                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17744                    '</style>';
17745         } else { 
17746             
17747         }
17748         
17749         st +=  '<style type="text/css">' +
17750             'IMG { cursor: pointer } ' +
17751         '</style>';
17752
17753         
17754         return '<html><head>' + st  +
17755             //<style type="text/css">' +
17756             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
17757             //'</style>' +
17758             ' </head><body class="roo-htmleditor-body"></body></html>';
17759     },
17760
17761     // private
17762     onRender : function(ct, position)
17763     {
17764         var _t = this;
17765         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
17766         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
17767         
17768         
17769         this.el.dom.style.border = '0 none';
17770         this.el.dom.setAttribute('tabIndex', -1);
17771         this.el.addClass('x-hidden hide');
17772         
17773         
17774         
17775         if(Roo.isIE){ // fix IE 1px bogus margin
17776             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
17777         }
17778        
17779         
17780         this.frameId = Roo.id();
17781         
17782          
17783         
17784         var iframe = this.owner.wrap.createChild({
17785             tag: 'iframe',
17786             cls: 'form-control', // bootstrap..
17787             id: this.frameId,
17788             name: this.frameId,
17789             frameBorder : 'no',
17790             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
17791         }, this.el
17792         );
17793         
17794         
17795         this.iframe = iframe.dom;
17796
17797          this.assignDocWin();
17798         
17799         this.doc.designMode = 'on';
17800        
17801         this.doc.open();
17802         this.doc.write(this.getDocMarkup());
17803         this.doc.close();
17804
17805         
17806         var task = { // must defer to wait for browser to be ready
17807             run : function(){
17808                 //console.log("run task?" + this.doc.readyState);
17809                 this.assignDocWin();
17810                 if(this.doc.body || this.doc.readyState == 'complete'){
17811                     try {
17812                         this.doc.designMode="on";
17813                     } catch (e) {
17814                         return;
17815                     }
17816                     Roo.TaskMgr.stop(task);
17817                     this.initEditor.defer(10, this);
17818                 }
17819             },
17820             interval : 10,
17821             duration: 10000,
17822             scope: this
17823         };
17824         Roo.TaskMgr.start(task);
17825
17826     },
17827
17828     // private
17829     onResize : function(w, h)
17830     {
17831          Roo.log('resize: ' +w + ',' + h );
17832         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
17833         if(!this.iframe){
17834             return;
17835         }
17836         if(typeof w == 'number'){
17837             
17838             this.iframe.style.width = w + 'px';
17839         }
17840         if(typeof h == 'number'){
17841             
17842             this.iframe.style.height = h + 'px';
17843             if(this.doc){
17844                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
17845             }
17846         }
17847         
17848     },
17849
17850     /**
17851      * Toggles the editor between standard and source edit mode.
17852      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
17853      */
17854     toggleSourceEdit : function(sourceEditMode){
17855         
17856         this.sourceEditMode = sourceEditMode === true;
17857         
17858         if(this.sourceEditMode){
17859  
17860             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
17861             
17862         }else{
17863             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
17864             //this.iframe.className = '';
17865             this.deferFocus();
17866         }
17867         //this.setSize(this.owner.wrap.getSize());
17868         //this.fireEvent('editmodechange', this, this.sourceEditMode);
17869     },
17870
17871     
17872   
17873
17874     /**
17875      * Protected method that will not generally be called directly. If you need/want
17876      * custom HTML cleanup, this is the method you should override.
17877      * @param {String} html The HTML to be cleaned
17878      * return {String} The cleaned HTML
17879      */
17880     cleanHtml : function(html){
17881         html = String(html);
17882         if(html.length > 5){
17883             if(Roo.isSafari){ // strip safari nonsense
17884                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
17885             }
17886         }
17887         if(html == '&nbsp;'){
17888             html = '';
17889         }
17890         return html;
17891     },
17892
17893     /**
17894      * HTML Editor -> Textarea
17895      * Protected method that will not generally be called directly. Syncs the contents
17896      * of the editor iframe with the textarea.
17897      */
17898     syncValue : function(){
17899         if(this.initialized){
17900             var bd = (this.doc.body || this.doc.documentElement);
17901             //this.cleanUpPaste(); -- this is done else where and causes havoc..
17902             var html = bd.innerHTML;
17903             if(Roo.isSafari){
17904                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
17905                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
17906                 if(m && m[1]){
17907                     html = '<div style="'+m[0]+'">' + html + '</div>';
17908                 }
17909             }
17910             html = this.cleanHtml(html);
17911             // fix up the special chars.. normaly like back quotes in word...
17912             // however we do not want to do this with chinese..
17913             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
17914                 var cc = b.charCodeAt();
17915                 if (
17916                     (cc >= 0x4E00 && cc < 0xA000 ) ||
17917                     (cc >= 0x3400 && cc < 0x4E00 ) ||
17918                     (cc >= 0xf900 && cc < 0xfb00 )
17919                 ) {
17920                         return b;
17921                 }
17922                 return "&#"+cc+";" 
17923             });
17924             if(this.owner.fireEvent('beforesync', this, html) !== false){
17925                 this.el.dom.value = html;
17926                 this.owner.fireEvent('sync', this, html);
17927             }
17928         }
17929     },
17930
17931     /**
17932      * Protected method that will not generally be called directly. Pushes the value of the textarea
17933      * into the iframe editor.
17934      */
17935     pushValue : function(){
17936         if(this.initialized){
17937             var v = this.el.dom.value.trim();
17938             
17939 //            if(v.length < 1){
17940 //                v = '&#160;';
17941 //            }
17942             
17943             if(this.owner.fireEvent('beforepush', this, v) !== false){
17944                 var d = (this.doc.body || this.doc.documentElement);
17945                 d.innerHTML = v;
17946                 this.cleanUpPaste();
17947                 this.el.dom.value = d.innerHTML;
17948                 this.owner.fireEvent('push', this, v);
17949             }
17950         }
17951     },
17952
17953     // private
17954     deferFocus : function(){
17955         this.focus.defer(10, this);
17956     },
17957
17958     // doc'ed in Field
17959     focus : function(){
17960         if(this.win && !this.sourceEditMode){
17961             this.win.focus();
17962         }else{
17963             this.el.focus();
17964         }
17965     },
17966     
17967     assignDocWin: function()
17968     {
17969         var iframe = this.iframe;
17970         
17971          if(Roo.isIE){
17972             this.doc = iframe.contentWindow.document;
17973             this.win = iframe.contentWindow;
17974         } else {
17975 //            if (!Roo.get(this.frameId)) {
17976 //                return;
17977 //            }
17978 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17979 //            this.win = Roo.get(this.frameId).dom.contentWindow;
17980             
17981             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
17982                 return;
17983             }
17984             
17985             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
17986             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
17987         }
17988     },
17989     
17990     // private
17991     initEditor : function(){
17992         //console.log("INIT EDITOR");
17993         this.assignDocWin();
17994         
17995         
17996         
17997         this.doc.designMode="on";
17998         this.doc.open();
17999         this.doc.write(this.getDocMarkup());
18000         this.doc.close();
18001         
18002         var dbody = (this.doc.body || this.doc.documentElement);
18003         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18004         // this copies styles from the containing element into thsi one..
18005         // not sure why we need all of this..
18006         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18007         
18008         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18009         //ss['background-attachment'] = 'fixed'; // w3c
18010         dbody.bgProperties = 'fixed'; // ie
18011         //Roo.DomHelper.applyStyles(dbody, ss);
18012         Roo.EventManager.on(this.doc, {
18013             //'mousedown': this.onEditorEvent,
18014             'mouseup': this.onEditorEvent,
18015             'dblclick': this.onEditorEvent,
18016             'click': this.onEditorEvent,
18017             'keyup': this.onEditorEvent,
18018             buffer:100,
18019             scope: this
18020         });
18021         if(Roo.isGecko){
18022             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18023         }
18024         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18025             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18026         }
18027         this.initialized = true;
18028
18029         this.owner.fireEvent('initialize', this);
18030         this.pushValue();
18031     },
18032
18033     // private
18034     onDestroy : function(){
18035         
18036         
18037         
18038         if(this.rendered){
18039             
18040             //for (var i =0; i < this.toolbars.length;i++) {
18041             //    // fixme - ask toolbars for heights?
18042             //    this.toolbars[i].onDestroy();
18043            // }
18044             
18045             //this.wrap.dom.innerHTML = '';
18046             //this.wrap.remove();
18047         }
18048     },
18049
18050     // private
18051     onFirstFocus : function(){
18052         
18053         this.assignDocWin();
18054         
18055         
18056         this.activated = true;
18057          
18058     
18059         if(Roo.isGecko){ // prevent silly gecko errors
18060             this.win.focus();
18061             var s = this.win.getSelection();
18062             if(!s.focusNode || s.focusNode.nodeType != 3){
18063                 var r = s.getRangeAt(0);
18064                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18065                 r.collapse(true);
18066                 this.deferFocus();
18067             }
18068             try{
18069                 this.execCmd('useCSS', true);
18070                 this.execCmd('styleWithCSS', false);
18071             }catch(e){}
18072         }
18073         this.owner.fireEvent('activate', this);
18074     },
18075
18076     // private
18077     adjustFont: function(btn){
18078         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18079         //if(Roo.isSafari){ // safari
18080         //    adjust *= 2;
18081        // }
18082         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18083         if(Roo.isSafari){ // safari
18084             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18085             v =  (v < 10) ? 10 : v;
18086             v =  (v > 48) ? 48 : v;
18087             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18088             
18089         }
18090         
18091         
18092         v = Math.max(1, v+adjust);
18093         
18094         this.execCmd('FontSize', v  );
18095     },
18096
18097     onEditorEvent : function(e){
18098         this.owner.fireEvent('editorevent', this, e);
18099       //  this.updateToolbar();
18100         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18101     },
18102
18103     insertTag : function(tg)
18104     {
18105         // could be a bit smarter... -> wrap the current selected tRoo..
18106         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18107             
18108             range = this.createRange(this.getSelection());
18109             var wrappingNode = this.doc.createElement(tg.toLowerCase());
18110             wrappingNode.appendChild(range.extractContents());
18111             range.insertNode(wrappingNode);
18112
18113             return;
18114             
18115             
18116             
18117         }
18118         this.execCmd("formatblock",   tg);
18119         
18120     },
18121     
18122     insertText : function(txt)
18123     {
18124         
18125         
18126         var range = this.createRange();
18127         range.deleteContents();
18128                //alert(Sender.getAttribute('label'));
18129                
18130         range.insertNode(this.doc.createTextNode(txt));
18131     } ,
18132     
18133      
18134
18135     /**
18136      * Executes a Midas editor command on the editor document and performs necessary focus and
18137      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18138      * @param {String} cmd The Midas command
18139      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18140      */
18141     relayCmd : function(cmd, value){
18142         this.win.focus();
18143         this.execCmd(cmd, value);
18144         this.owner.fireEvent('editorevent', this);
18145         //this.updateToolbar();
18146         this.owner.deferFocus();
18147     },
18148
18149     /**
18150      * Executes a Midas editor command directly on the editor document.
18151      * For visual commands, you should use {@link #relayCmd} instead.
18152      * <b>This should only be called after the editor is initialized.</b>
18153      * @param {String} cmd The Midas command
18154      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18155      */
18156     execCmd : function(cmd, value){
18157         this.doc.execCommand(cmd, false, value === undefined ? null : value);
18158         this.syncValue();
18159     },
18160  
18161  
18162    
18163     /**
18164      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18165      * to insert tRoo.
18166      * @param {String} text | dom node.. 
18167      */
18168     insertAtCursor : function(text)
18169     {
18170         
18171         
18172         
18173         if(!this.activated){
18174             return;
18175         }
18176         /*
18177         if(Roo.isIE){
18178             this.win.focus();
18179             var r = this.doc.selection.createRange();
18180             if(r){
18181                 r.collapse(true);
18182                 r.pasteHTML(text);
18183                 this.syncValue();
18184                 this.deferFocus();
18185             
18186             }
18187             return;
18188         }
18189         */
18190         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18191             this.win.focus();
18192             
18193             
18194             // from jquery ui (MIT licenced)
18195             var range, node;
18196             var win = this.win;
18197             
18198             if (win.getSelection && win.getSelection().getRangeAt) {
18199                 range = win.getSelection().getRangeAt(0);
18200                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18201                 range.insertNode(node);
18202             } else if (win.document.selection && win.document.selection.createRange) {
18203                 // no firefox support
18204                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18205                 win.document.selection.createRange().pasteHTML(txt);
18206             } else {
18207                 // no firefox support
18208                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18209                 this.execCmd('InsertHTML', txt);
18210             } 
18211             
18212             this.syncValue();
18213             
18214             this.deferFocus();
18215         }
18216     },
18217  // private
18218     mozKeyPress : function(e){
18219         if(e.ctrlKey){
18220             var c = e.getCharCode(), cmd;
18221           
18222             if(c > 0){
18223                 c = String.fromCharCode(c).toLowerCase();
18224                 switch(c){
18225                     case 'b':
18226                         cmd = 'bold';
18227                         break;
18228                     case 'i':
18229                         cmd = 'italic';
18230                         break;
18231                     
18232                     case 'u':
18233                         cmd = 'underline';
18234                         break;
18235                     
18236                     case 'v':
18237                         this.cleanUpPaste.defer(100, this);
18238                         return;
18239                         
18240                 }
18241                 if(cmd){
18242                     this.win.focus();
18243                     this.execCmd(cmd);
18244                     this.deferFocus();
18245                     e.preventDefault();
18246                 }
18247                 
18248             }
18249         }
18250     },
18251
18252     // private
18253     fixKeys : function(){ // load time branching for fastest keydown performance
18254         if(Roo.isIE){
18255             return function(e){
18256                 var k = e.getKey(), r;
18257                 if(k == e.TAB){
18258                     e.stopEvent();
18259                     r = this.doc.selection.createRange();
18260                     if(r){
18261                         r.collapse(true);
18262                         r.pasteHTML('&#160;&#160;&#160;&#160;');
18263                         this.deferFocus();
18264                     }
18265                     return;
18266                 }
18267                 
18268                 if(k == e.ENTER){
18269                     r = this.doc.selection.createRange();
18270                     if(r){
18271                         var target = r.parentElement();
18272                         if(!target || target.tagName.toLowerCase() != 'li'){
18273                             e.stopEvent();
18274                             r.pasteHTML('<br />');
18275                             r.collapse(false);
18276                             r.select();
18277                         }
18278                     }
18279                 }
18280                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18281                     this.cleanUpPaste.defer(100, this);
18282                     return;
18283                 }
18284                 
18285                 
18286             };
18287         }else if(Roo.isOpera){
18288             return function(e){
18289                 var k = e.getKey();
18290                 if(k == e.TAB){
18291                     e.stopEvent();
18292                     this.win.focus();
18293                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
18294                     this.deferFocus();
18295                 }
18296                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18297                     this.cleanUpPaste.defer(100, this);
18298                     return;
18299                 }
18300                 
18301             };
18302         }else if(Roo.isSafari){
18303             return function(e){
18304                 var k = e.getKey();
18305                 
18306                 if(k == e.TAB){
18307                     e.stopEvent();
18308                     this.execCmd('InsertText','\t');
18309                     this.deferFocus();
18310                     return;
18311                 }
18312                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18313                     this.cleanUpPaste.defer(100, this);
18314                     return;
18315                 }
18316                 
18317              };
18318         }
18319     }(),
18320     
18321     getAllAncestors: function()
18322     {
18323         var p = this.getSelectedNode();
18324         var a = [];
18325         if (!p) {
18326             a.push(p); // push blank onto stack..
18327             p = this.getParentElement();
18328         }
18329         
18330         
18331         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18332             a.push(p);
18333             p = p.parentNode;
18334         }
18335         a.push(this.doc.body);
18336         return a;
18337     },
18338     lastSel : false,
18339     lastSelNode : false,
18340     
18341     
18342     getSelection : function() 
18343     {
18344         this.assignDocWin();
18345         return Roo.isIE ? this.doc.selection : this.win.getSelection();
18346     },
18347     
18348     getSelectedNode: function() 
18349     {
18350         // this may only work on Gecko!!!
18351         
18352         // should we cache this!!!!
18353         
18354         
18355         
18356          
18357         var range = this.createRange(this.getSelection()).cloneRange();
18358         
18359         if (Roo.isIE) {
18360             var parent = range.parentElement();
18361             while (true) {
18362                 var testRange = range.duplicate();
18363                 testRange.moveToElementText(parent);
18364                 if (testRange.inRange(range)) {
18365                     break;
18366                 }
18367                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18368                     break;
18369                 }
18370                 parent = parent.parentElement;
18371             }
18372             return parent;
18373         }
18374         
18375         // is ancestor a text element.
18376         var ac =  range.commonAncestorContainer;
18377         if (ac.nodeType == 3) {
18378             ac = ac.parentNode;
18379         }
18380         
18381         var ar = ac.childNodes;
18382          
18383         var nodes = [];
18384         var other_nodes = [];
18385         var has_other_nodes = false;
18386         for (var i=0;i<ar.length;i++) {
18387             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
18388                 continue;
18389             }
18390             // fullly contained node.
18391             
18392             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18393                 nodes.push(ar[i]);
18394                 continue;
18395             }
18396             
18397             // probably selected..
18398             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18399                 other_nodes.push(ar[i]);
18400                 continue;
18401             }
18402             // outer..
18403             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
18404                 continue;
18405             }
18406             
18407             
18408             has_other_nodes = true;
18409         }
18410         if (!nodes.length && other_nodes.length) {
18411             nodes= other_nodes;
18412         }
18413         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18414             return false;
18415         }
18416         
18417         return nodes[0];
18418     },
18419     createRange: function(sel)
18420     {
18421         // this has strange effects when using with 
18422         // top toolbar - not sure if it's a great idea.
18423         //this.editor.contentWindow.focus();
18424         if (typeof sel != "undefined") {
18425             try {
18426                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18427             } catch(e) {
18428                 return this.doc.createRange();
18429             }
18430         } else {
18431             return this.doc.createRange();
18432         }
18433     },
18434     getParentElement: function()
18435     {
18436         
18437         this.assignDocWin();
18438         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18439         
18440         var range = this.createRange(sel);
18441          
18442         try {
18443             var p = range.commonAncestorContainer;
18444             while (p.nodeType == 3) { // text node
18445                 p = p.parentNode;
18446             }
18447             return p;
18448         } catch (e) {
18449             return null;
18450         }
18451     
18452     },
18453     /***
18454      *
18455      * Range intersection.. the hard stuff...
18456      *  '-1' = before
18457      *  '0' = hits..
18458      *  '1' = after.
18459      *         [ -- selected range --- ]
18460      *   [fail]                        [fail]
18461      *
18462      *    basically..
18463      *      if end is before start or  hits it. fail.
18464      *      if start is after end or hits it fail.
18465      *
18466      *   if either hits (but other is outside. - then it's not 
18467      *   
18468      *    
18469      **/
18470     
18471     
18472     // @see http://www.thismuchiknow.co.uk/?p=64.
18473     rangeIntersectsNode : function(range, node)
18474     {
18475         var nodeRange = node.ownerDocument.createRange();
18476         try {
18477             nodeRange.selectNode(node);
18478         } catch (e) {
18479             nodeRange.selectNodeContents(node);
18480         }
18481     
18482         var rangeStartRange = range.cloneRange();
18483         rangeStartRange.collapse(true);
18484     
18485         var rangeEndRange = range.cloneRange();
18486         rangeEndRange.collapse(false);
18487     
18488         var nodeStartRange = nodeRange.cloneRange();
18489         nodeStartRange.collapse(true);
18490     
18491         var nodeEndRange = nodeRange.cloneRange();
18492         nodeEndRange.collapse(false);
18493     
18494         return rangeStartRange.compareBoundaryPoints(
18495                  Range.START_TO_START, nodeEndRange) == -1 &&
18496                rangeEndRange.compareBoundaryPoints(
18497                  Range.START_TO_START, nodeStartRange) == 1;
18498         
18499          
18500     },
18501     rangeCompareNode : function(range, node)
18502     {
18503         var nodeRange = node.ownerDocument.createRange();
18504         try {
18505             nodeRange.selectNode(node);
18506         } catch (e) {
18507             nodeRange.selectNodeContents(node);
18508         }
18509         
18510         
18511         range.collapse(true);
18512     
18513         nodeRange.collapse(true);
18514      
18515         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18516         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
18517          
18518         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18519         
18520         var nodeIsBefore   =  ss == 1;
18521         var nodeIsAfter    = ee == -1;
18522         
18523         if (nodeIsBefore && nodeIsAfter)
18524             return 0; // outer
18525         if (!nodeIsBefore && nodeIsAfter)
18526             return 1; //right trailed.
18527         
18528         if (nodeIsBefore && !nodeIsAfter)
18529             return 2;  // left trailed.
18530         // fully contined.
18531         return 3;
18532     },
18533
18534     // private? - in a new class?
18535     cleanUpPaste :  function()
18536     {
18537         // cleans up the whole document..
18538         Roo.log('cleanuppaste');
18539         
18540         this.cleanUpChildren(this.doc.body);
18541         var clean = this.cleanWordChars(this.doc.body.innerHTML);
18542         if (clean != this.doc.body.innerHTML) {
18543             this.doc.body.innerHTML = clean;
18544         }
18545         
18546     },
18547     
18548     cleanWordChars : function(input) {// change the chars to hex code
18549         var he = Roo.HtmlEditorCore;
18550         
18551         var output = input;
18552         Roo.each(he.swapCodes, function(sw) { 
18553             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18554             
18555             output = output.replace(swapper, sw[1]);
18556         });
18557         
18558         return output;
18559     },
18560     
18561     
18562     cleanUpChildren : function (n)
18563     {
18564         if (!n.childNodes.length) {
18565             return;
18566         }
18567         for (var i = n.childNodes.length-1; i > -1 ; i--) {
18568            this.cleanUpChild(n.childNodes[i]);
18569         }
18570     },
18571     
18572     
18573         
18574     
18575     cleanUpChild : function (node)
18576     {
18577         var ed = this;
18578         //console.log(node);
18579         if (node.nodeName == "#text") {
18580             // clean up silly Windows -- stuff?
18581             return; 
18582         }
18583         if (node.nodeName == "#comment") {
18584             node.parentNode.removeChild(node);
18585             // clean up silly Windows -- stuff?
18586             return; 
18587         }
18588         var lcname = node.tagName.toLowerCase();
18589         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18590         // whitelist of tags..
18591         
18592         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18593             // remove node.
18594             node.parentNode.removeChild(node);
18595             return;
18596             
18597         }
18598         
18599         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18600         
18601         // remove <a name=....> as rendering on yahoo mailer is borked with this.
18602         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18603         
18604         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18605         //    remove_keep_children = true;
18606         //}
18607         
18608         if (remove_keep_children) {
18609             this.cleanUpChildren(node);
18610             // inserts everything just before this node...
18611             while (node.childNodes.length) {
18612                 var cn = node.childNodes[0];
18613                 node.removeChild(cn);
18614                 node.parentNode.insertBefore(cn, node);
18615             }
18616             node.parentNode.removeChild(node);
18617             return;
18618         }
18619         
18620         if (!node.attributes || !node.attributes.length) {
18621             this.cleanUpChildren(node);
18622             return;
18623         }
18624         
18625         function cleanAttr(n,v)
18626         {
18627             
18628             if (v.match(/^\./) || v.match(/^\//)) {
18629                 return;
18630             }
18631             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18632                 return;
18633             }
18634             if (v.match(/^#/)) {
18635                 return;
18636             }
18637 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18638             node.removeAttribute(n);
18639             
18640         }
18641         
18642         var cwhite = this.cwhite;
18643         var cblack = this.cblack;
18644             
18645         function cleanStyle(n,v)
18646         {
18647             if (v.match(/expression/)) { //XSS?? should we even bother..
18648                 node.removeAttribute(n);
18649                 return;
18650             }
18651             
18652             var parts = v.split(/;/);
18653             var clean = [];
18654             
18655             Roo.each(parts, function(p) {
18656                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
18657                 if (!p.length) {
18658                     return true;
18659                 }
18660                 var l = p.split(':').shift().replace(/\s+/g,'');
18661                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
18662                 
18663                 if ( cwhite.length && cblack.indexOf(l) > -1) {
18664 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18665                     //node.removeAttribute(n);
18666                     return true;
18667                 }
18668                 //Roo.log()
18669                 // only allow 'c whitelisted system attributes'
18670                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
18671 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
18672                     //node.removeAttribute(n);
18673                     return true;
18674                 }
18675                 
18676                 
18677                  
18678                 
18679                 clean.push(p);
18680                 return true;
18681             });
18682             if (clean.length) { 
18683                 node.setAttribute(n, clean.join(';'));
18684             } else {
18685                 node.removeAttribute(n);
18686             }
18687             
18688         }
18689         
18690         
18691         for (var i = node.attributes.length-1; i > -1 ; i--) {
18692             var a = node.attributes[i];
18693             //console.log(a);
18694             
18695             if (a.name.toLowerCase().substr(0,2)=='on')  {
18696                 node.removeAttribute(a.name);
18697                 continue;
18698             }
18699             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
18700                 node.removeAttribute(a.name);
18701                 continue;
18702             }
18703             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
18704                 cleanAttr(a.name,a.value); // fixme..
18705                 continue;
18706             }
18707             if (a.name == 'style') {
18708                 cleanStyle(a.name,a.value);
18709                 continue;
18710             }
18711             /// clean up MS crap..
18712             // tecnically this should be a list of valid class'es..
18713             
18714             
18715             if (a.name == 'class') {
18716                 if (a.value.match(/^Mso/)) {
18717                     node.className = '';
18718                 }
18719                 
18720                 if (a.value.match(/body/)) {
18721                     node.className = '';
18722                 }
18723                 continue;
18724             }
18725             
18726             // style cleanup!?
18727             // class cleanup?
18728             
18729         }
18730         
18731         
18732         this.cleanUpChildren(node);
18733         
18734         
18735     },
18736     /**
18737      * Clean up MS wordisms...
18738      */
18739     cleanWord : function(node)
18740     {
18741         var _t = this;
18742         var cleanWordChildren = function()
18743         {
18744             if (!node.childNodes.length) {
18745                 return;
18746             }
18747             for (var i = node.childNodes.length-1; i > -1 ; i--) {
18748                _t.cleanWord(node.childNodes[i]);
18749             }
18750         }
18751         
18752         
18753         if (!node) {
18754             this.cleanWord(this.doc.body);
18755             return;
18756         }
18757         if (node.nodeName == "#text") {
18758             // clean up silly Windows -- stuff?
18759             return; 
18760         }
18761         if (node.nodeName == "#comment") {
18762             node.parentNode.removeChild(node);
18763             // clean up silly Windows -- stuff?
18764             return; 
18765         }
18766         
18767         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
18768             node.parentNode.removeChild(node);
18769             return;
18770         }
18771         
18772         // remove - but keep children..
18773         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
18774             while (node.childNodes.length) {
18775                 var cn = node.childNodes[0];
18776                 node.removeChild(cn);
18777                 node.parentNode.insertBefore(cn, node);
18778             }
18779             node.parentNode.removeChild(node);
18780             cleanWordChildren();
18781             return;
18782         }
18783         // clean styles
18784         if (node.className.length) {
18785             
18786             var cn = node.className.split(/\W+/);
18787             var cna = [];
18788             Roo.each(cn, function(cls) {
18789                 if (cls.match(/Mso[a-zA-Z]+/)) {
18790                     return;
18791                 }
18792                 cna.push(cls);
18793             });
18794             node.className = cna.length ? cna.join(' ') : '';
18795             if (!cna.length) {
18796                 node.removeAttribute("class");
18797             }
18798         }
18799         
18800         if (node.hasAttribute("lang")) {
18801             node.removeAttribute("lang");
18802         }
18803         
18804         if (node.hasAttribute("style")) {
18805             
18806             var styles = node.getAttribute("style").split(";");
18807             var nstyle = [];
18808             Roo.each(styles, function(s) {
18809                 if (!s.match(/:/)) {
18810                     return;
18811                 }
18812                 var kv = s.split(":");
18813                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
18814                     return;
18815                 }
18816                 // what ever is left... we allow.
18817                 nstyle.push(s);
18818             });
18819             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
18820             if (!nstyle.length) {
18821                 node.removeAttribute('style');
18822             }
18823         }
18824         
18825         cleanWordChildren();
18826         
18827         
18828     },
18829     domToHTML : function(currentElement, depth, nopadtext) {
18830         
18831         depth = depth || 0;
18832         nopadtext = nopadtext || false;
18833     
18834         if (!currentElement) {
18835             return this.domToHTML(this.doc.body);
18836         }
18837         
18838         //Roo.log(currentElement);
18839         var j;
18840         var allText = false;
18841         var nodeName = currentElement.nodeName;
18842         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
18843         
18844         if  (nodeName == '#text') {
18845             
18846             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
18847         }
18848         
18849         
18850         var ret = '';
18851         if (nodeName != 'BODY') {
18852              
18853             var i = 0;
18854             // Prints the node tagName, such as <A>, <IMG>, etc
18855             if (tagName) {
18856                 var attr = [];
18857                 for(i = 0; i < currentElement.attributes.length;i++) {
18858                     // quoting?
18859                     var aname = currentElement.attributes.item(i).name;
18860                     if (!currentElement.attributes.item(i).value.length) {
18861                         continue;
18862                     }
18863                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
18864                 }
18865                 
18866                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
18867             } 
18868             else {
18869                 
18870                 // eack
18871             }
18872         } else {
18873             tagName = false;
18874         }
18875         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
18876             return ret;
18877         }
18878         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
18879             nopadtext = true;
18880         }
18881         
18882         
18883         // Traverse the tree
18884         i = 0;
18885         var currentElementChild = currentElement.childNodes.item(i);
18886         var allText = true;
18887         var innerHTML  = '';
18888         lastnode = '';
18889         while (currentElementChild) {
18890             // Formatting code (indent the tree so it looks nice on the screen)
18891             var nopad = nopadtext;
18892             if (lastnode == 'SPAN') {
18893                 nopad  = true;
18894             }
18895             // text
18896             if  (currentElementChild.nodeName == '#text') {
18897                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
18898                 toadd = nopadtext ? toadd : toadd.trim();
18899                 if (!nopad && toadd.length > 80) {
18900                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
18901                 }
18902                 innerHTML  += toadd;
18903                 
18904                 i++;
18905                 currentElementChild = currentElement.childNodes.item(i);
18906                 lastNode = '';
18907                 continue;
18908             }
18909             allText = false;
18910             
18911             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
18912                 
18913             // Recursively traverse the tree structure of the child node
18914             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
18915             lastnode = currentElementChild.nodeName;
18916             i++;
18917             currentElementChild=currentElement.childNodes.item(i);
18918         }
18919         
18920         ret += innerHTML;
18921         
18922         if (!allText) {
18923                 // The remaining code is mostly for formatting the tree
18924             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
18925         }
18926         
18927         
18928         if (tagName) {
18929             ret+= "</"+tagName+">";
18930         }
18931         return ret;
18932         
18933     },
18934         
18935     applyBlacklists : function()
18936     {
18937         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
18938         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
18939         
18940         this.white = [];
18941         this.black = [];
18942         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
18943             if (b.indexOf(tag) > -1) {
18944                 return;
18945             }
18946             this.white.push(tag);
18947             
18948         }, this);
18949         
18950         Roo.each(w, function(tag) {
18951             if (b.indexOf(tag) > -1) {
18952                 return;
18953             }
18954             if (this.white.indexOf(tag) > -1) {
18955                 return;
18956             }
18957             this.white.push(tag);
18958             
18959         }, this);
18960         
18961         
18962         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
18963             if (w.indexOf(tag) > -1) {
18964                 return;
18965             }
18966             this.black.push(tag);
18967             
18968         }, this);
18969         
18970         Roo.each(b, function(tag) {
18971             if (w.indexOf(tag) > -1) {
18972                 return;
18973             }
18974             if (this.black.indexOf(tag) > -1) {
18975                 return;
18976             }
18977             this.black.push(tag);
18978             
18979         }, this);
18980         
18981         
18982         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
18983         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
18984         
18985         this.cwhite = [];
18986         this.cblack = [];
18987         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
18988             if (b.indexOf(tag) > -1) {
18989                 return;
18990             }
18991             this.cwhite.push(tag);
18992             
18993         }, this);
18994         
18995         Roo.each(w, function(tag) {
18996             if (b.indexOf(tag) > -1) {
18997                 return;
18998             }
18999             if (this.cwhite.indexOf(tag) > -1) {
19000                 return;
19001             }
19002             this.cwhite.push(tag);
19003             
19004         }, this);
19005         
19006         
19007         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19008             if (w.indexOf(tag) > -1) {
19009                 return;
19010             }
19011             this.cblack.push(tag);
19012             
19013         }, this);
19014         
19015         Roo.each(b, function(tag) {
19016             if (w.indexOf(tag) > -1) {
19017                 return;
19018             }
19019             if (this.cblack.indexOf(tag) > -1) {
19020                 return;
19021             }
19022             this.cblack.push(tag);
19023             
19024         }, this);
19025     },
19026     
19027     setStylesheets : function(stylesheets)
19028     {
19029         if(typeof(stylesheets) == 'string'){
19030             Roo.get(this.iframe.contentDocument.head).createChild({
19031                 tag : 'link',
19032                 rel : 'stylesheet',
19033                 type : 'text/css',
19034                 href : stylesheets
19035             });
19036             
19037             return;
19038         }
19039         var _this = this;
19040      
19041         Roo.each(stylesheets, function(s) {
19042             if(!s.length){
19043                 return;
19044             }
19045             
19046             Roo.get(_this.iframe.contentDocument.head).createChild({
19047                 tag : 'link',
19048                 rel : 'stylesheet',
19049                 type : 'text/css',
19050                 href : s
19051             });
19052         });
19053
19054         
19055     },
19056     
19057     removeStylesheets : function()
19058     {
19059         var _this = this;
19060         
19061         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19062             s.remove();
19063         });
19064     }
19065     
19066     // hide stuff that is not compatible
19067     /**
19068      * @event blur
19069      * @hide
19070      */
19071     /**
19072      * @event change
19073      * @hide
19074      */
19075     /**
19076      * @event focus
19077      * @hide
19078      */
19079     /**
19080      * @event specialkey
19081      * @hide
19082      */
19083     /**
19084      * @cfg {String} fieldClass @hide
19085      */
19086     /**
19087      * @cfg {String} focusClass @hide
19088      */
19089     /**
19090      * @cfg {String} autoCreate @hide
19091      */
19092     /**
19093      * @cfg {String} inputType @hide
19094      */
19095     /**
19096      * @cfg {String} invalidClass @hide
19097      */
19098     /**
19099      * @cfg {String} invalidText @hide
19100      */
19101     /**
19102      * @cfg {String} msgFx @hide
19103      */
19104     /**
19105      * @cfg {String} validateOnBlur @hide
19106      */
19107 });
19108
19109 Roo.HtmlEditorCore.white = [
19110         'area', 'br', 'img', 'input', 'hr', 'wbr',
19111         
19112        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
19113        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
19114        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
19115        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
19116        'table',   'ul',         'xmp', 
19117        
19118        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
19119       'thead',   'tr', 
19120      
19121       'dir', 'menu', 'ol', 'ul', 'dl',
19122        
19123       'embed',  'object'
19124 ];
19125
19126
19127 Roo.HtmlEditorCore.black = [
19128     //    'embed',  'object', // enable - backend responsiblity to clean thiese
19129         'applet', // 
19130         'base',   'basefont', 'bgsound', 'blink',  'body', 
19131         'frame',  'frameset', 'head',    'html',   'ilayer', 
19132         'iframe', 'layer',  'link',     'meta',    'object',   
19133         'script', 'style' ,'title',  'xml' // clean later..
19134 ];
19135 Roo.HtmlEditorCore.clean = [
19136     'script', 'style', 'title', 'xml'
19137 ];
19138 Roo.HtmlEditorCore.remove = [
19139     'font'
19140 ];
19141 // attributes..
19142
19143 Roo.HtmlEditorCore.ablack = [
19144     'on'
19145 ];
19146     
19147 Roo.HtmlEditorCore.aclean = [ 
19148     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
19149 ];
19150
19151 // protocols..
19152 Roo.HtmlEditorCore.pwhite= [
19153         'http',  'https',  'mailto'
19154 ];
19155
19156 // white listed style attributes.
19157 Roo.HtmlEditorCore.cwhite= [
19158       //  'text-align', /// default is to allow most things..
19159       
19160          
19161 //        'font-size'//??
19162 ];
19163
19164 // black listed style attributes.
19165 Roo.HtmlEditorCore.cblack= [
19166       //  'font-size' -- this can be set by the project 
19167 ];
19168
19169
19170 Roo.HtmlEditorCore.swapCodes   =[ 
19171     [    8211, "--" ], 
19172     [    8212, "--" ], 
19173     [    8216,  "'" ],  
19174     [    8217, "'" ],  
19175     [    8220, '"' ],  
19176     [    8221, '"' ],  
19177     [    8226, "*" ],  
19178     [    8230, "..." ]
19179 ]; 
19180
19181     /*
19182  * - LGPL
19183  *
19184  * HtmlEditor
19185  * 
19186  */
19187
19188 /**
19189  * @class Roo.bootstrap.HtmlEditor
19190  * @extends Roo.bootstrap.TextArea
19191  * Bootstrap HtmlEditor class
19192
19193  * @constructor
19194  * Create a new HtmlEditor
19195  * @param {Object} config The config object
19196  */
19197
19198 Roo.bootstrap.HtmlEditor = function(config){
19199     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19200     if (!this.toolbars) {
19201         this.toolbars = [];
19202     }
19203     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19204     this.addEvents({
19205             /**
19206              * @event initialize
19207              * Fires when the editor is fully initialized (including the iframe)
19208              * @param {HtmlEditor} this
19209              */
19210             initialize: true,
19211             /**
19212              * @event activate
19213              * Fires when the editor is first receives the focus. Any insertion must wait
19214              * until after this event.
19215              * @param {HtmlEditor} this
19216              */
19217             activate: true,
19218              /**
19219              * @event beforesync
19220              * Fires before the textarea is updated with content from the editor iframe. Return false
19221              * to cancel the sync.
19222              * @param {HtmlEditor} this
19223              * @param {String} html
19224              */
19225             beforesync: true,
19226              /**
19227              * @event beforepush
19228              * Fires before the iframe editor is updated with content from the textarea. Return false
19229              * to cancel the push.
19230              * @param {HtmlEditor} this
19231              * @param {String} html
19232              */
19233             beforepush: true,
19234              /**
19235              * @event sync
19236              * Fires when the textarea is updated with content from the editor iframe.
19237              * @param {HtmlEditor} this
19238              * @param {String} html
19239              */
19240             sync: true,
19241              /**
19242              * @event push
19243              * Fires when the iframe editor is updated with content from the textarea.
19244              * @param {HtmlEditor} this
19245              * @param {String} html
19246              */
19247             push: true,
19248              /**
19249              * @event editmodechange
19250              * Fires when the editor switches edit modes
19251              * @param {HtmlEditor} this
19252              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19253              */
19254             editmodechange: true,
19255             /**
19256              * @event editorevent
19257              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19258              * @param {HtmlEditor} this
19259              */
19260             editorevent: true,
19261             /**
19262              * @event firstfocus
19263              * Fires when on first focus - needed by toolbars..
19264              * @param {HtmlEditor} this
19265              */
19266             firstfocus: true,
19267             /**
19268              * @event autosave
19269              * Auto save the htmlEditor value as a file into Events
19270              * @param {HtmlEditor} this
19271              */
19272             autosave: true,
19273             /**
19274              * @event savedpreview
19275              * preview the saved version of htmlEditor
19276              * @param {HtmlEditor} this
19277              */
19278             savedpreview: true
19279         });
19280 };
19281
19282
19283 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
19284     
19285     
19286       /**
19287      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19288      */
19289     toolbars : false,
19290    
19291      /**
19292      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
19293      *                        Roo.resizable.
19294      */
19295     resizable : false,
19296      /**
19297      * @cfg {Number} height (in pixels)
19298      */   
19299     height: 300,
19300    /**
19301      * @cfg {Number} width (in pixels)
19302      */   
19303     width: false,
19304     
19305     /**
19306      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19307      * 
19308      */
19309     stylesheets: false,
19310     
19311     // id of frame..
19312     frameId: false,
19313     
19314     // private properties
19315     validationEvent : false,
19316     deferHeight: true,
19317     initialized : false,
19318     activated : false,
19319     
19320     onFocus : Roo.emptyFn,
19321     iframePad:3,
19322     hideMode:'offsets',
19323     
19324     
19325     tbContainer : false,
19326     
19327     toolbarContainer :function() {
19328         return this.wrap.select('.x-html-editor-tb',true).first();
19329     },
19330
19331     /**
19332      * Protected method that will not generally be called directly. It
19333      * is called when the editor creates its toolbar. Override this method if you need to
19334      * add custom toolbar buttons.
19335      * @param {HtmlEditor} editor
19336      */
19337     createToolbar : function(){
19338         
19339         Roo.log("create toolbars");
19340         
19341         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19342         this.toolbars[0].render(this.toolbarContainer());
19343         
19344         return;
19345         
19346 //        if (!editor.toolbars || !editor.toolbars.length) {
19347 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19348 //        }
19349 //        
19350 //        for (var i =0 ; i < editor.toolbars.length;i++) {
19351 //            editor.toolbars[i] = Roo.factory(
19352 //                    typeof(editor.toolbars[i]) == 'string' ?
19353 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
19354 //                Roo.bootstrap.HtmlEditor);
19355 //            editor.toolbars[i].init(editor);
19356 //        }
19357     },
19358
19359      
19360     // private
19361     onRender : function(ct, position)
19362     {
19363        // Roo.log("Call onRender: " + this.xtype);
19364         var _t = this;
19365         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19366       
19367         this.wrap = this.inputEl().wrap({
19368             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19369         });
19370         
19371         this.editorcore.onRender(ct, position);
19372          
19373         if (this.resizable) {
19374             this.resizeEl = new Roo.Resizable(this.wrap, {
19375                 pinned : true,
19376                 wrap: true,
19377                 dynamic : true,
19378                 minHeight : this.height,
19379                 height: this.height,
19380                 handles : this.resizable,
19381                 width: this.width,
19382                 listeners : {
19383                     resize : function(r, w, h) {
19384                         _t.onResize(w,h); // -something
19385                     }
19386                 }
19387             });
19388             
19389         }
19390         this.createToolbar(this);
19391        
19392         
19393         if(!this.width && this.resizable){
19394             this.setSize(this.wrap.getSize());
19395         }
19396         if (this.resizeEl) {
19397             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19398             // should trigger onReize..
19399         }
19400         
19401     },
19402
19403     // private
19404     onResize : function(w, h)
19405     {
19406         Roo.log('resize: ' +w + ',' + h );
19407         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19408         var ew = false;
19409         var eh = false;
19410         
19411         if(this.inputEl() ){
19412             if(typeof w == 'number'){
19413                 var aw = w - this.wrap.getFrameWidth('lr');
19414                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19415                 ew = aw;
19416             }
19417             if(typeof h == 'number'){
19418                  var tbh = -11;  // fixme it needs to tool bar size!
19419                 for (var i =0; i < this.toolbars.length;i++) {
19420                     // fixme - ask toolbars for heights?
19421                     tbh += this.toolbars[i].el.getHeight();
19422                     //if (this.toolbars[i].footer) {
19423                     //    tbh += this.toolbars[i].footer.el.getHeight();
19424                     //}
19425                 }
19426               
19427                 
19428                 
19429                 
19430                 
19431                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19432                 ah -= 5; // knock a few pixes off for look..
19433                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19434                 var eh = ah;
19435             }
19436         }
19437         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19438         this.editorcore.onResize(ew,eh);
19439         
19440     },
19441
19442     /**
19443      * Toggles the editor between standard and source edit mode.
19444      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19445      */
19446     toggleSourceEdit : function(sourceEditMode)
19447     {
19448         this.editorcore.toggleSourceEdit(sourceEditMode);
19449         
19450         if(this.editorcore.sourceEditMode){
19451             Roo.log('editor - showing textarea');
19452             
19453 //            Roo.log('in');
19454 //            Roo.log(this.syncValue());
19455             this.syncValue();
19456             this.inputEl().removeClass(['hide', 'x-hidden']);
19457             this.inputEl().dom.removeAttribute('tabIndex');
19458             this.inputEl().focus();
19459         }else{
19460             Roo.log('editor - hiding textarea');
19461 //            Roo.log('out')
19462 //            Roo.log(this.pushValue()); 
19463             this.pushValue();
19464             
19465             this.inputEl().addClass(['hide', 'x-hidden']);
19466             this.inputEl().dom.setAttribute('tabIndex', -1);
19467             //this.deferFocus();
19468         }
19469          
19470         if(this.resizable){
19471             this.setSize(this.wrap.getSize());
19472         }
19473         
19474         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19475     },
19476  
19477     // private (for BoxComponent)
19478     adjustSize : Roo.BoxComponent.prototype.adjustSize,
19479
19480     // private (for BoxComponent)
19481     getResizeEl : function(){
19482         return this.wrap;
19483     },
19484
19485     // private (for BoxComponent)
19486     getPositionEl : function(){
19487         return this.wrap;
19488     },
19489
19490     // private
19491     initEvents : function(){
19492         this.originalValue = this.getValue();
19493     },
19494
19495 //    /**
19496 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19497 //     * @method
19498 //     */
19499 //    markInvalid : Roo.emptyFn,
19500 //    /**
19501 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19502 //     * @method
19503 //     */
19504 //    clearInvalid : Roo.emptyFn,
19505
19506     setValue : function(v){
19507         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19508         this.editorcore.pushValue();
19509     },
19510
19511      
19512     // private
19513     deferFocus : function(){
19514         this.focus.defer(10, this);
19515     },
19516
19517     // doc'ed in Field
19518     focus : function(){
19519         this.editorcore.focus();
19520         
19521     },
19522       
19523
19524     // private
19525     onDestroy : function(){
19526         
19527         
19528         
19529         if(this.rendered){
19530             
19531             for (var i =0; i < this.toolbars.length;i++) {
19532                 // fixme - ask toolbars for heights?
19533                 this.toolbars[i].onDestroy();
19534             }
19535             
19536             this.wrap.dom.innerHTML = '';
19537             this.wrap.remove();
19538         }
19539     },
19540
19541     // private
19542     onFirstFocus : function(){
19543         //Roo.log("onFirstFocus");
19544         this.editorcore.onFirstFocus();
19545          for (var i =0; i < this.toolbars.length;i++) {
19546             this.toolbars[i].onFirstFocus();
19547         }
19548         
19549     },
19550     
19551     // private
19552     syncValue : function()
19553     {   
19554         this.editorcore.syncValue();
19555     },
19556     
19557     pushValue : function()
19558     {   
19559         this.editorcore.pushValue();
19560     }
19561      
19562     
19563     // hide stuff that is not compatible
19564     /**
19565      * @event blur
19566      * @hide
19567      */
19568     /**
19569      * @event change
19570      * @hide
19571      */
19572     /**
19573      * @event focus
19574      * @hide
19575      */
19576     /**
19577      * @event specialkey
19578      * @hide
19579      */
19580     /**
19581      * @cfg {String} fieldClass @hide
19582      */
19583     /**
19584      * @cfg {String} focusClass @hide
19585      */
19586     /**
19587      * @cfg {String} autoCreate @hide
19588      */
19589     /**
19590      * @cfg {String} inputType @hide
19591      */
19592     /**
19593      * @cfg {String} invalidClass @hide
19594      */
19595     /**
19596      * @cfg {String} invalidText @hide
19597      */
19598     /**
19599      * @cfg {String} msgFx @hide
19600      */
19601     /**
19602      * @cfg {String} validateOnBlur @hide
19603      */
19604 });
19605  
19606     
19607    
19608    
19609    
19610       
19611 Roo.namespace('Roo.bootstrap.htmleditor');
19612 /**
19613  * @class Roo.bootstrap.HtmlEditorToolbar1
19614  * Basic Toolbar
19615  * 
19616  * Usage:
19617  *
19618  new Roo.bootstrap.HtmlEditor({
19619     ....
19620     toolbars : [
19621         new Roo.bootstrap.HtmlEditorToolbar1({
19622             disable : { fonts: 1 , format: 1, ..., ... , ...],
19623             btns : [ .... ]
19624         })
19625     }
19626      
19627  * 
19628  * @cfg {Object} disable List of elements to disable..
19629  * @cfg {Array} btns List of additional buttons.
19630  * 
19631  * 
19632  * NEEDS Extra CSS? 
19633  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19634  */
19635  
19636 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19637 {
19638     
19639     Roo.apply(this, config);
19640     
19641     // default disabled, based on 'good practice'..
19642     this.disable = this.disable || {};
19643     Roo.applyIf(this.disable, {
19644         fontSize : true,
19645         colors : true,
19646         specialElements : true
19647     });
19648     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19649     
19650     this.editor = config.editor;
19651     this.editorcore = config.editor.editorcore;
19652     
19653     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
19654     
19655     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
19656     // dont call parent... till later.
19657 }
19658 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
19659      
19660     bar : true,
19661     
19662     editor : false,
19663     editorcore : false,
19664     
19665     
19666     formats : [
19667         "p" ,  
19668         "h1","h2","h3","h4","h5","h6", 
19669         "pre", "code", 
19670         "abbr", "acronym", "address", "cite", "samp", "var",
19671         'div','span'
19672     ],
19673     
19674     onRender : function(ct, position)
19675     {
19676        // Roo.log("Call onRender: " + this.xtype);
19677         
19678        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
19679        Roo.log(this.el);
19680        this.el.dom.style.marginBottom = '0';
19681        var _this = this;
19682        var editorcore = this.editorcore;
19683        var editor= this.editor;
19684        
19685        var children = [];
19686        var btn = function(id,cmd , toggle, handler){
19687        
19688             var  event = toggle ? 'toggle' : 'click';
19689        
19690             var a = {
19691                 size : 'sm',
19692                 xtype: 'Button',
19693                 xns: Roo.bootstrap,
19694                 glyphicon : id,
19695                 cmd : id || cmd,
19696                 enableToggle:toggle !== false,
19697                 //html : 'submit'
19698                 pressed : toggle ? false : null,
19699                 listeners : {}
19700             }
19701             a.listeners[toggle ? 'toggle' : 'click'] = function() {
19702                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
19703             }
19704             children.push(a);
19705             return a;
19706        }
19707         
19708         var style = {
19709                 xtype: 'Button',
19710                 size : 'sm',
19711                 xns: Roo.bootstrap,
19712                 glyphicon : 'font',
19713                 //html : 'submit'
19714                 menu : {
19715                     xtype: 'Menu',
19716                     xns: Roo.bootstrap,
19717                     items:  []
19718                 }
19719         };
19720         Roo.each(this.formats, function(f) {
19721             style.menu.items.push({
19722                 xtype :'MenuItem',
19723                 xns: Roo.bootstrap,
19724                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
19725                 tagname : f,
19726                 listeners : {
19727                     click : function()
19728                     {
19729                         editorcore.insertTag(this.tagname);
19730                         editor.focus();
19731                     }
19732                 }
19733                 
19734             });
19735         });
19736          children.push(style);   
19737             
19738             
19739         btn('bold',false,true);
19740         btn('italic',false,true);
19741         btn('align-left', 'justifyleft',true);
19742         btn('align-center', 'justifycenter',true);
19743         btn('align-right' , 'justifyright',true);
19744         btn('link', false, false, function(btn) {
19745             //Roo.log("create link?");
19746             var url = prompt(this.createLinkText, this.defaultLinkValue);
19747             if(url && url != 'http:/'+'/'){
19748                 this.editorcore.relayCmd('createlink', url);
19749             }
19750         }),
19751         btn('list','insertunorderedlist',true);
19752         btn('pencil', false,true, function(btn){
19753                 Roo.log(this);
19754                 
19755                 this.toggleSourceEdit(btn.pressed);
19756         });
19757         /*
19758         var cog = {
19759                 xtype: 'Button',
19760                 size : 'sm',
19761                 xns: Roo.bootstrap,
19762                 glyphicon : 'cog',
19763                 //html : 'submit'
19764                 menu : {
19765                     xtype: 'Menu',
19766                     xns: Roo.bootstrap,
19767                     items:  []
19768                 }
19769         };
19770         
19771         cog.menu.items.push({
19772             xtype :'MenuItem',
19773             xns: Roo.bootstrap,
19774             html : Clean styles,
19775             tagname : f,
19776             listeners : {
19777                 click : function()
19778                 {
19779                     editorcore.insertTag(this.tagname);
19780                     editor.focus();
19781                 }
19782             }
19783             
19784         });
19785        */
19786         
19787          
19788        this.xtype = 'NavSimplebar';
19789         
19790         for(var i=0;i< children.length;i++) {
19791             
19792             this.buttons.add(this.addxtypeChild(children[i]));
19793             
19794         }
19795         
19796         editor.on('editorevent', this.updateToolbar, this);
19797     },
19798     onBtnClick : function(id)
19799     {
19800        this.editorcore.relayCmd(id);
19801        this.editorcore.focus();
19802     },
19803     
19804     /**
19805      * Protected method that will not generally be called directly. It triggers
19806      * a toolbar update by reading the markup state of the current selection in the editor.
19807      */
19808     updateToolbar: function(){
19809
19810         if(!this.editorcore.activated){
19811             this.editor.onFirstFocus(); // is this neeed?
19812             return;
19813         }
19814
19815         var btns = this.buttons; 
19816         var doc = this.editorcore.doc;
19817         btns.get('bold').setActive(doc.queryCommandState('bold'));
19818         btns.get('italic').setActive(doc.queryCommandState('italic'));
19819         //btns.get('underline').setActive(doc.queryCommandState('underline'));
19820         
19821         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
19822         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
19823         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
19824         
19825         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
19826         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
19827          /*
19828         
19829         var ans = this.editorcore.getAllAncestors();
19830         if (this.formatCombo) {
19831             
19832             
19833             var store = this.formatCombo.store;
19834             this.formatCombo.setValue("");
19835             for (var i =0; i < ans.length;i++) {
19836                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
19837                     // select it..
19838                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
19839                     break;
19840                 }
19841             }
19842         }
19843         
19844         
19845         
19846         // hides menus... - so this cant be on a menu...
19847         Roo.bootstrap.MenuMgr.hideAll();
19848         */
19849         Roo.bootstrap.MenuMgr.hideAll();
19850         //this.editorsyncValue();
19851     },
19852     onFirstFocus: function() {
19853         this.buttons.each(function(item){
19854            item.enable();
19855         });
19856     },
19857     toggleSourceEdit : function(sourceEditMode){
19858         
19859           
19860         if(sourceEditMode){
19861             Roo.log("disabling buttons");
19862            this.buttons.each( function(item){
19863                 if(item.cmd != 'pencil'){
19864                     item.disable();
19865                 }
19866             });
19867           
19868         }else{
19869             Roo.log("enabling buttons");
19870             if(this.editorcore.initialized){
19871                 this.buttons.each( function(item){
19872                     item.enable();
19873                 });
19874             }
19875             
19876         }
19877         Roo.log("calling toggole on editor");
19878         // tell the editor that it's been pressed..
19879         this.editor.toggleSourceEdit(sourceEditMode);
19880        
19881     }
19882 });
19883
19884
19885
19886
19887
19888 /**
19889  * @class Roo.bootstrap.Table.AbstractSelectionModel
19890  * @extends Roo.util.Observable
19891  * Abstract base class for grid SelectionModels.  It provides the interface that should be
19892  * implemented by descendant classes.  This class should not be directly instantiated.
19893  * @constructor
19894  */
19895 Roo.bootstrap.Table.AbstractSelectionModel = function(){
19896     this.locked = false;
19897     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
19898 };
19899
19900
19901 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
19902     /** @ignore Called by the grid automatically. Do not call directly. */
19903     init : function(grid){
19904         this.grid = grid;
19905         this.initEvents();
19906     },
19907
19908     /**
19909      * Locks the selections.
19910      */
19911     lock : function(){
19912         this.locked = true;
19913     },
19914
19915     /**
19916      * Unlocks the selections.
19917      */
19918     unlock : function(){
19919         this.locked = false;
19920     },
19921
19922     /**
19923      * Returns true if the selections are locked.
19924      * @return {Boolean}
19925      */
19926     isLocked : function(){
19927         return this.locked;
19928     }
19929 });
19930 /**
19931  * @extends Roo.bootstrap.Table.AbstractSelectionModel
19932  * @class Roo.bootstrap.Table.RowSelectionModel
19933  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
19934  * It supports multiple selections and keyboard selection/navigation. 
19935  * @constructor
19936  * @param {Object} config
19937  */
19938
19939 Roo.bootstrap.Table.RowSelectionModel = function(config){
19940     Roo.apply(this, config);
19941     this.selections = new Roo.util.MixedCollection(false, function(o){
19942         return o.id;
19943     });
19944
19945     this.last = false;
19946     this.lastActive = false;
19947
19948     this.addEvents({
19949         /**
19950              * @event selectionchange
19951              * Fires when the selection changes
19952              * @param {SelectionModel} this
19953              */
19954             "selectionchange" : true,
19955         /**
19956              * @event afterselectionchange
19957              * Fires after the selection changes (eg. by key press or clicking)
19958              * @param {SelectionModel} this
19959              */
19960             "afterselectionchange" : true,
19961         /**
19962              * @event beforerowselect
19963              * Fires when a row is selected being selected, return false to cancel.
19964              * @param {SelectionModel} this
19965              * @param {Number} rowIndex The selected index
19966              * @param {Boolean} keepExisting False if other selections will be cleared
19967              */
19968             "beforerowselect" : true,
19969         /**
19970              * @event rowselect
19971              * Fires when a row is selected.
19972              * @param {SelectionModel} this
19973              * @param {Number} rowIndex The selected index
19974              * @param {Roo.data.Record} r The record
19975              */
19976             "rowselect" : true,
19977         /**
19978              * @event rowdeselect
19979              * Fires when a row is deselected.
19980              * @param {SelectionModel} this
19981              * @param {Number} rowIndex The selected index
19982              */
19983         "rowdeselect" : true
19984     });
19985     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
19986     this.locked = false;
19987 };
19988
19989 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
19990     /**
19991      * @cfg {Boolean} singleSelect
19992      * True to allow selection of only one row at a time (defaults to false)
19993      */
19994     singleSelect : false,
19995
19996     // private
19997     initEvents : function(){
19998
19999         if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20000             this.grid.on("mousedown", this.handleMouseDown, this);
20001         }else{ // allow click to work like normal
20002             this.grid.on("rowclick", this.handleDragableRowClick, this);
20003         }
20004
20005         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20006             "up" : function(e){
20007                 if(!e.shiftKey){
20008                     this.selectPrevious(e.shiftKey);
20009                 }else if(this.last !== false && this.lastActive !== false){
20010                     var last = this.last;
20011                     this.selectRange(this.last,  this.lastActive-1);
20012                     this.grid.getView().focusRow(this.lastActive);
20013                     if(last !== false){
20014                         this.last = last;
20015                     }
20016                 }else{
20017                     this.selectFirstRow();
20018                 }
20019                 this.fireEvent("afterselectionchange", this);
20020             },
20021             "down" : function(e){
20022                 if(!e.shiftKey){
20023                     this.selectNext(e.shiftKey);
20024                 }else if(this.last !== false && this.lastActive !== false){
20025                     var last = this.last;
20026                     this.selectRange(this.last,  this.lastActive+1);
20027                     this.grid.getView().focusRow(this.lastActive);
20028                     if(last !== false){
20029                         this.last = last;
20030                     }
20031                 }else{
20032                     this.selectFirstRow();
20033                 }
20034                 this.fireEvent("afterselectionchange", this);
20035             },
20036             scope: this
20037         });
20038
20039         var view = this.grid.view;
20040         view.on("refresh", this.onRefresh, this);
20041         view.on("rowupdated", this.onRowUpdated, this);
20042         view.on("rowremoved", this.onRemove, this);
20043     },
20044
20045     // private
20046     onRefresh : function(){
20047         var ds = this.grid.dataSource, i, v = this.grid.view;
20048         var s = this.selections;
20049         s.each(function(r){
20050             if((i = ds.indexOfId(r.id)) != -1){
20051                 v.onRowSelect(i);
20052             }else{
20053                 s.remove(r);
20054             }
20055         });
20056     },
20057
20058     // private
20059     onRemove : function(v, index, r){
20060         this.selections.remove(r);
20061     },
20062
20063     // private
20064     onRowUpdated : function(v, index, r){
20065         if(this.isSelected(r)){
20066             v.onRowSelect(index);
20067         }
20068     },
20069
20070     /**
20071      * Select records.
20072      * @param {Array} records The records to select
20073      * @param {Boolean} keepExisting (optional) True to keep existing selections
20074      */
20075     selectRecords : function(records, keepExisting){
20076         if(!keepExisting){
20077             this.clearSelections();
20078         }
20079         var ds = this.grid.dataSource;
20080         for(var i = 0, len = records.length; i < len; i++){
20081             this.selectRow(ds.indexOf(records[i]), true);
20082         }
20083     },
20084
20085     /**
20086      * Gets the number of selected rows.
20087      * @return {Number}
20088      */
20089     getCount : function(){
20090         return this.selections.length;
20091     },
20092
20093     /**
20094      * Selects the first row in the grid.
20095      */
20096     selectFirstRow : function(){
20097         this.selectRow(0);
20098     },
20099
20100     /**
20101      * Select the last row.
20102      * @param {Boolean} keepExisting (optional) True to keep existing selections
20103      */
20104     selectLastRow : function(keepExisting){
20105         this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20106     },
20107
20108     /**
20109      * Selects the row immediately following the last selected row.
20110      * @param {Boolean} keepExisting (optional) True to keep existing selections
20111      */
20112     selectNext : function(keepExisting){
20113         if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20114             this.selectRow(this.last+1, keepExisting);
20115             this.grid.getView().focusRow(this.last);
20116         }
20117     },
20118
20119     /**
20120      * Selects the row that precedes the last selected row.
20121      * @param {Boolean} keepExisting (optional) True to keep existing selections
20122      */
20123     selectPrevious : function(keepExisting){
20124         if(this.last){
20125             this.selectRow(this.last-1, keepExisting);
20126             this.grid.getView().focusRow(this.last);
20127         }
20128     },
20129
20130     /**
20131      * Returns the selected records
20132      * @return {Array} Array of selected records
20133      */
20134     getSelections : function(){
20135         return [].concat(this.selections.items);
20136     },
20137
20138     /**
20139      * Returns the first selected record.
20140      * @return {Record}
20141      */
20142     getSelected : function(){
20143         return this.selections.itemAt(0);
20144     },
20145
20146
20147     /**
20148      * Clears all selections.
20149      */
20150     clearSelections : function(fast){
20151         if(this.locked) return;
20152         if(fast !== true){
20153             var ds = this.grid.dataSource;
20154             var s = this.selections;
20155             s.each(function(r){
20156                 this.deselectRow(ds.indexOfId(r.id));
20157             }, this);
20158             s.clear();
20159         }else{
20160             this.selections.clear();
20161         }
20162         this.last = false;
20163     },
20164
20165
20166     /**
20167      * Selects all rows.
20168      */
20169     selectAll : function(){
20170         if(this.locked) return;
20171         this.selections.clear();
20172         for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20173             this.selectRow(i, true);
20174         }
20175     },
20176
20177     /**
20178      * Returns True if there is a selection.
20179      * @return {Boolean}
20180      */
20181     hasSelection : function(){
20182         return this.selections.length > 0;
20183     },
20184
20185     /**
20186      * Returns True if the specified row is selected.
20187      * @param {Number/Record} record The record or index of the record to check
20188      * @return {Boolean}
20189      */
20190     isSelected : function(index){
20191         var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20192         return (r && this.selections.key(r.id) ? true : false);
20193     },
20194
20195     /**
20196      * Returns True if the specified record id is selected.
20197      * @param {String} id The id of record to check
20198      * @return {Boolean}
20199      */
20200     isIdSelected : function(id){
20201         return (this.selections.key(id) ? true : false);
20202     },
20203
20204     // private
20205     handleMouseDown : function(e, t){
20206         var view = this.grid.getView(), rowIndex;
20207         if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20208             return;
20209         };
20210         if(e.shiftKey && this.last !== false){
20211             var last = this.last;
20212             this.selectRange(last, rowIndex, e.ctrlKey);
20213             this.last = last; // reset the last
20214             view.focusRow(rowIndex);
20215         }else{
20216             var isSelected = this.isSelected(rowIndex);
20217             if(e.button !== 0 && isSelected){
20218                 view.focusRow(rowIndex);
20219             }else if(e.ctrlKey && isSelected){
20220                 this.deselectRow(rowIndex);
20221             }else if(!isSelected){
20222                 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20223                 view.focusRow(rowIndex);
20224             }
20225         }
20226         this.fireEvent("afterselectionchange", this);
20227     },
20228     // private
20229     handleDragableRowClick :  function(grid, rowIndex, e) 
20230     {
20231         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20232             this.selectRow(rowIndex, false);
20233             grid.view.focusRow(rowIndex);
20234              this.fireEvent("afterselectionchange", this);
20235         }
20236     },
20237     
20238     /**
20239      * Selects multiple rows.
20240      * @param {Array} rows Array of the indexes of the row to select
20241      * @param {Boolean} keepExisting (optional) True to keep existing selections
20242      */
20243     selectRows : function(rows, keepExisting){
20244         if(!keepExisting){
20245             this.clearSelections();
20246         }
20247         for(var i = 0, len = rows.length; i < len; i++){
20248             this.selectRow(rows[i], true);
20249         }
20250     },
20251
20252     /**
20253      * Selects a range of rows. All rows in between startRow and endRow are also selected.
20254      * @param {Number} startRow The index of the first row in the range
20255      * @param {Number} endRow The index of the last row in the range
20256      * @param {Boolean} keepExisting (optional) True to retain existing selections
20257      */
20258     selectRange : function(startRow, endRow, keepExisting){
20259         if(this.locked) return;
20260         if(!keepExisting){
20261             this.clearSelections();
20262         }
20263         if(startRow <= endRow){
20264             for(var i = startRow; i <= endRow; i++){
20265                 this.selectRow(i, true);
20266             }
20267         }else{
20268             for(var i = startRow; i >= endRow; i--){
20269                 this.selectRow(i, true);
20270             }
20271         }
20272     },
20273
20274     /**
20275      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20276      * @param {Number} startRow The index of the first row in the range
20277      * @param {Number} endRow The index of the last row in the range
20278      */
20279     deselectRange : function(startRow, endRow, preventViewNotify){
20280         if(this.locked) return;
20281         for(var i = startRow; i <= endRow; i++){
20282             this.deselectRow(i, preventViewNotify);
20283         }
20284     },
20285
20286     /**
20287      * Selects a row.
20288      * @param {Number} row The index of the row to select
20289      * @param {Boolean} keepExisting (optional) True to keep existing selections
20290      */
20291     selectRow : function(index, keepExisting, preventViewNotify){
20292         if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20293         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20294             if(!keepExisting || this.singleSelect){
20295                 this.clearSelections();
20296             }
20297             var r = this.grid.dataSource.getAt(index);
20298             this.selections.add(r);
20299             this.last = this.lastActive = index;
20300             if(!preventViewNotify){
20301                 this.grid.getView().onRowSelect(index);
20302             }
20303             this.fireEvent("rowselect", this, index, r);
20304             this.fireEvent("selectionchange", this);
20305         }
20306     },
20307
20308     /**
20309      * Deselects a row.
20310      * @param {Number} row The index of the row to deselect
20311      */
20312     deselectRow : function(index, preventViewNotify){
20313         if(this.locked) return;
20314         if(this.last == index){
20315             this.last = false;
20316         }
20317         if(this.lastActive == index){
20318             this.lastActive = false;
20319         }
20320         var r = this.grid.dataSource.getAt(index);
20321         this.selections.remove(r);
20322         if(!preventViewNotify){
20323             this.grid.getView().onRowDeselect(index);
20324         }
20325         this.fireEvent("rowdeselect", this, index);
20326         this.fireEvent("selectionchange", this);
20327     },
20328
20329     // private
20330     restoreLast : function(){
20331         if(this._last){
20332             this.last = this._last;
20333         }
20334     },
20335
20336     // private
20337     acceptsNav : function(row, col, cm){
20338         return !cm.isHidden(col) && cm.isCellEditable(col, row);
20339     },
20340
20341     // private
20342     onEditorKey : function(field, e){
20343         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20344         if(k == e.TAB){
20345             e.stopEvent();
20346             ed.completeEdit();
20347             if(e.shiftKey){
20348                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20349             }else{
20350                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20351             }
20352         }else if(k == e.ENTER && !e.ctrlKey){
20353             e.stopEvent();
20354             ed.completeEdit();
20355             if(e.shiftKey){
20356                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20357             }else{
20358                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20359             }
20360         }else if(k == e.ESC){
20361             ed.cancelEdit();
20362         }
20363         if(newCell){
20364             g.startEditing(newCell[0], newCell[1]);
20365         }
20366     }
20367 });/*
20368  * Based on:
20369  * Ext JS Library 1.1.1
20370  * Copyright(c) 2006-2007, Ext JS, LLC.
20371  *
20372  * Originally Released Under LGPL - original licence link has changed is not relivant.
20373  *
20374  * Fork - LGPL
20375  * <script type="text/javascript">
20376  */
20377  
20378 /**
20379  * @class Roo.bootstrap.PagingToolbar
20380  * @extends Roo.Row
20381  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20382  * @constructor
20383  * Create a new PagingToolbar
20384  * @param {Object} config The config object
20385  */
20386 Roo.bootstrap.PagingToolbar = function(config)
20387 {
20388     // old args format still supported... - xtype is prefered..
20389         // created from xtype...
20390     var ds = config.dataSource;
20391     this.toolbarItems = [];
20392     if (config.items) {
20393         this.toolbarItems = config.items;
20394 //        config.items = [];
20395     }
20396     
20397     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20398     this.ds = ds;
20399     this.cursor = 0;
20400     if (ds) { 
20401         this.bind(ds);
20402     }
20403     
20404     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20405     
20406 };
20407
20408 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20409     /**
20410      * @cfg {Roo.data.Store} dataSource
20411      * The underlying data store providing the paged data
20412      */
20413     /**
20414      * @cfg {String/HTMLElement/Element} container
20415      * container The id or element that will contain the toolbar
20416      */
20417     /**
20418      * @cfg {Boolean} displayInfo
20419      * True to display the displayMsg (defaults to false)
20420      */
20421     /**
20422      * @cfg {Number} pageSize
20423      * The number of records to display per page (defaults to 20)
20424      */
20425     pageSize: 20,
20426     /**
20427      * @cfg {String} displayMsg
20428      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20429      */
20430     displayMsg : 'Displaying {0} - {1} of {2}',
20431     /**
20432      * @cfg {String} emptyMsg
20433      * The message to display when no records are found (defaults to "No data to display")
20434      */
20435     emptyMsg : 'No data to display',
20436     /**
20437      * Customizable piece of the default paging text (defaults to "Page")
20438      * @type String
20439      */
20440     beforePageText : "Page",
20441     /**
20442      * Customizable piece of the default paging text (defaults to "of %0")
20443      * @type String
20444      */
20445     afterPageText : "of {0}",
20446     /**
20447      * Customizable piece of the default paging text (defaults to "First Page")
20448      * @type String
20449      */
20450     firstText : "First Page",
20451     /**
20452      * Customizable piece of the default paging text (defaults to "Previous Page")
20453      * @type String
20454      */
20455     prevText : "Previous Page",
20456     /**
20457      * Customizable piece of the default paging text (defaults to "Next Page")
20458      * @type String
20459      */
20460     nextText : "Next Page",
20461     /**
20462      * Customizable piece of the default paging text (defaults to "Last Page")
20463      * @type String
20464      */
20465     lastText : "Last Page",
20466     /**
20467      * Customizable piece of the default paging text (defaults to "Refresh")
20468      * @type String
20469      */
20470     refreshText : "Refresh",
20471
20472     buttons : false,
20473     // private
20474     onRender : function(ct, position) 
20475     {
20476         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20477         this.navgroup.parentId = this.id;
20478         this.navgroup.onRender(this.el, null);
20479         // add the buttons to the navgroup
20480         
20481         if(this.displayInfo){
20482             Roo.log(this.el.select('ul.navbar-nav',true).first());
20483             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20484             this.displayEl = this.el.select('.x-paging-info', true).first();
20485 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20486 //            this.displayEl = navel.el.select('span',true).first();
20487         }
20488         
20489         var _this = this;
20490         
20491         if(this.buttons){
20492             Roo.each(_this.buttons, function(e){
20493                Roo.factory(e).onRender(_this.el, null);
20494             });
20495         }
20496             
20497         Roo.each(_this.toolbarItems, function(e) {
20498             _this.navgroup.addItem(e);
20499         });
20500         
20501         
20502         this.first = this.navgroup.addItem({
20503             tooltip: this.firstText,
20504             cls: "prev",
20505             icon : 'fa fa-backward',
20506             disabled: true,
20507             preventDefault: true,
20508             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20509         });
20510         
20511         this.prev =  this.navgroup.addItem({
20512             tooltip: this.prevText,
20513             cls: "prev",
20514             icon : 'fa fa-step-backward',
20515             disabled: true,
20516             preventDefault: true,
20517             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
20518         });
20519     //this.addSeparator();
20520         
20521         
20522         var field = this.navgroup.addItem( {
20523             tagtype : 'span',
20524             cls : 'x-paging-position',
20525             
20526             html : this.beforePageText  +
20527                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20528                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
20529          } ); //?? escaped?
20530         
20531         this.field = field.el.select('input', true).first();
20532         this.field.on("keydown", this.onPagingKeydown, this);
20533         this.field.on("focus", function(){this.dom.select();});
20534     
20535     
20536         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
20537         //this.field.setHeight(18);
20538         //this.addSeparator();
20539         this.next = this.navgroup.addItem({
20540             tooltip: this.nextText,
20541             cls: "next",
20542             html : ' <i class="fa fa-step-forward">',
20543             disabled: true,
20544             preventDefault: true,
20545             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
20546         });
20547         this.last = this.navgroup.addItem({
20548             tooltip: this.lastText,
20549             icon : 'fa fa-forward',
20550             cls: "next",
20551             disabled: true,
20552             preventDefault: true,
20553             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
20554         });
20555     //this.addSeparator();
20556         this.loading = this.navgroup.addItem({
20557             tooltip: this.refreshText,
20558             icon: 'fa fa-refresh',
20559             preventDefault: true,
20560             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20561         });
20562
20563     },
20564
20565     // private
20566     updateInfo : function(){
20567         if(this.displayEl){
20568             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20569             var msg = count == 0 ?
20570                 this.emptyMsg :
20571                 String.format(
20572                     this.displayMsg,
20573                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
20574                 );
20575             this.displayEl.update(msg);
20576         }
20577     },
20578
20579     // private
20580     onLoad : function(ds, r, o){
20581        this.cursor = o.params ? o.params.start : 0;
20582        var d = this.getPageData(),
20583             ap = d.activePage,
20584             ps = d.pages;
20585         
20586        this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20587        this.field.dom.value = ap;
20588        this.first.setDisabled(ap == 1);
20589        this.prev.setDisabled(ap == 1);
20590        this.next.setDisabled(ap == ps);
20591        this.last.setDisabled(ap == ps);
20592        this.loading.enable();
20593        this.updateInfo();
20594     },
20595
20596     // private
20597     getPageData : function(){
20598         var total = this.ds.getTotalCount();
20599         return {
20600             total : total,
20601             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20602             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20603         };
20604     },
20605
20606     // private
20607     onLoadError : function(){
20608         this.loading.enable();
20609     },
20610
20611     // private
20612     onPagingKeydown : function(e){
20613         var k = e.getKey();
20614         var d = this.getPageData();
20615         if(k == e.RETURN){
20616             var v = this.field.dom.value, pageNum;
20617             if(!v || isNaN(pageNum = parseInt(v, 10))){
20618                 this.field.dom.value = d.activePage;
20619                 return;
20620             }
20621             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20622             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20623             e.stopEvent();
20624         }
20625         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))
20626         {
20627           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20628           this.field.dom.value = pageNum;
20629           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20630           e.stopEvent();
20631         }
20632         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20633         {
20634           var v = this.field.dom.value, pageNum; 
20635           var increment = (e.shiftKey) ? 10 : 1;
20636           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20637             increment *= -1;
20638           if(!v || isNaN(pageNum = parseInt(v, 10))) {
20639             this.field.dom.value = d.activePage;
20640             return;
20641           }
20642           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20643           {
20644             this.field.dom.value = parseInt(v, 10) + increment;
20645             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20646             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20647           }
20648           e.stopEvent();
20649         }
20650     },
20651
20652     // private
20653     beforeLoad : function(){
20654         if(this.loading){
20655             this.loading.disable();
20656         }
20657     },
20658
20659     // private
20660     onClick : function(which){
20661         
20662         var ds = this.ds;
20663         if (!ds) {
20664             return;
20665         }
20666         
20667         switch(which){
20668             case "first":
20669                 ds.load({params:{start: 0, limit: this.pageSize}});
20670             break;
20671             case "prev":
20672                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
20673             break;
20674             case "next":
20675                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
20676             break;
20677             case "last":
20678                 var total = ds.getTotalCount();
20679                 var extra = total % this.pageSize;
20680                 var lastStart = extra ? (total - extra) : total-this.pageSize;
20681                 ds.load({params:{start: lastStart, limit: this.pageSize}});
20682             break;
20683             case "refresh":
20684                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
20685             break;
20686         }
20687     },
20688
20689     /**
20690      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
20691      * @param {Roo.data.Store} store The data store to unbind
20692      */
20693     unbind : function(ds){
20694         ds.un("beforeload", this.beforeLoad, this);
20695         ds.un("load", this.onLoad, this);
20696         ds.un("loadexception", this.onLoadError, this);
20697         ds.un("remove", this.updateInfo, this);
20698         ds.un("add", this.updateInfo, this);
20699         this.ds = undefined;
20700     },
20701
20702     /**
20703      * Binds the paging toolbar to the specified {@link Roo.data.Store}
20704      * @param {Roo.data.Store} store The data store to bind
20705      */
20706     bind : function(ds){
20707         ds.on("beforeload", this.beforeLoad, this);
20708         ds.on("load", this.onLoad, this);
20709         ds.on("loadexception", this.onLoadError, this);
20710         ds.on("remove", this.updateInfo, this);
20711         ds.on("add", this.updateInfo, this);
20712         this.ds = ds;
20713     }
20714 });/*
20715  * - LGPL
20716  *
20717  * element
20718  * 
20719  */
20720
20721 /**
20722  * @class Roo.bootstrap.MessageBar
20723  * @extends Roo.bootstrap.Component
20724  * Bootstrap MessageBar class
20725  * @cfg {String} html contents of the MessageBar
20726  * @cfg {String} weight (info | success | warning | danger) default info
20727  * @cfg {String} beforeClass insert the bar before the given class
20728  * @cfg {Boolean} closable (true | false) default false
20729  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
20730  * 
20731  * @constructor
20732  * Create a new Element
20733  * @param {Object} config The config object
20734  */
20735
20736 Roo.bootstrap.MessageBar = function(config){
20737     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
20738 };
20739
20740 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
20741     
20742     html: '',
20743     weight: 'info',
20744     closable: false,
20745     fixed: false,
20746     beforeClass: 'bootstrap-sticky-wrap',
20747     
20748     getAutoCreate : function(){
20749         
20750         var cfg = {
20751             tag: 'div',
20752             cls: 'alert alert-dismissable alert-' + this.weight,
20753             cn: [
20754                 {
20755                     tag: 'span',
20756                     cls: 'message',
20757                     html: this.html || ''
20758                 }
20759             ]
20760         }
20761         
20762         if(this.fixed){
20763             cfg.cls += ' alert-messages-fixed';
20764         }
20765         
20766         if(this.closable){
20767             cfg.cn.push({
20768                 tag: 'button',
20769                 cls: 'close',
20770                 html: 'x'
20771             });
20772         }
20773         
20774         return cfg;
20775     },
20776     
20777     onRender : function(ct, position)
20778     {
20779         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
20780         
20781         if(!this.el){
20782             var cfg = Roo.apply({},  this.getAutoCreate());
20783             cfg.id = Roo.id();
20784             
20785             if (this.cls) {
20786                 cfg.cls += ' ' + this.cls;
20787             }
20788             if (this.style) {
20789                 cfg.style = this.style;
20790             }
20791             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
20792             
20793             this.el.setVisibilityMode(Roo.Element.DISPLAY);
20794         }
20795         
20796         this.el.select('>button.close').on('click', this.hide, this);
20797         
20798     },
20799     
20800     show : function()
20801     {
20802         if (!this.rendered) {
20803             this.render();
20804         }
20805         
20806         this.el.show();
20807         
20808         this.fireEvent('show', this);
20809         
20810     },
20811     
20812     hide : function()
20813     {
20814         if (!this.rendered) {
20815             this.render();
20816         }
20817         
20818         this.el.hide();
20819         
20820         this.fireEvent('hide', this);
20821     },
20822     
20823     update : function()
20824     {
20825 //        var e = this.el.dom.firstChild;
20826 //        
20827 //        if(this.closable){
20828 //            e = e.nextSibling;
20829 //        }
20830 //        
20831 //        e.data = this.html || '';
20832
20833         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
20834     }
20835    
20836 });
20837
20838  
20839
20840      /*
20841  * - LGPL
20842  *
20843  * Graph
20844  * 
20845  */
20846
20847
20848 /**
20849  * @class Roo.bootstrap.Graph
20850  * @extends Roo.bootstrap.Component
20851  * Bootstrap Graph class
20852 > Prameters
20853  -sm {number} sm 4
20854  -md {number} md 5
20855  @cfg {String} graphtype  bar | vbar | pie
20856  @cfg {number} g_x coodinator | centre x (pie)
20857  @cfg {number} g_y coodinator | centre y (pie)
20858  @cfg {number} g_r radius (pie)
20859  @cfg {number} g_height height of the chart (respected by all elements in the set)
20860  @cfg {number} g_width width of the chart (respected by all elements in the set)
20861  @cfg {Object} title The title of the chart
20862     
20863  -{Array}  values
20864  -opts (object) options for the chart 
20865      o {
20866      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
20867      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
20868      o vgutter (number)
20869      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.
20870      o stacked (boolean) whether or not to tread values as in a stacked bar chart
20871      o to
20872      o stretch (boolean)
20873      o }
20874  -opts (object) options for the pie
20875      o{
20876      o cut
20877      o startAngle (number)
20878      o endAngle (number)
20879      } 
20880  *
20881  * @constructor
20882  * Create a new Input
20883  * @param {Object} config The config object
20884  */
20885
20886 Roo.bootstrap.Graph = function(config){
20887     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
20888     
20889     this.addEvents({
20890         // img events
20891         /**
20892          * @event click
20893          * The img click event for the img.
20894          * @param {Roo.EventObject} e
20895          */
20896         "click" : true
20897     });
20898 };
20899
20900 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
20901     
20902     sm: 4,
20903     md: 5,
20904     graphtype: 'bar',
20905     g_height: 250,
20906     g_width: 400,
20907     g_x: 50,
20908     g_y: 50,
20909     g_r: 30,
20910     opts:{
20911         //g_colors: this.colors,
20912         g_type: 'soft',
20913         g_gutter: '20%'
20914
20915     },
20916     title : false,
20917
20918     getAutoCreate : function(){
20919         
20920         var cfg = {
20921             tag: 'div',
20922             html : null
20923         }
20924         
20925         
20926         return  cfg;
20927     },
20928
20929     onRender : function(ct,position){
20930         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
20931         this.raphael = Raphael(this.el.dom);
20932         
20933                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20934                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20935                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
20936                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
20937                 /*
20938                 r.text(160, 10, "Single Series Chart").attr(txtattr);
20939                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
20940                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
20941                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
20942                 
20943                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
20944                 r.barchart(330, 10, 300, 220, data1);
20945                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
20946                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
20947                 */
20948                 
20949                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20950                 // r.barchart(30, 30, 560, 250,  xdata, {
20951                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
20952                 //     axis : "0 0 1 1",
20953                 //     axisxlabels :  xdata
20954                 //     //yvalues : cols,
20955                    
20956                 // });
20957 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
20958 //        
20959 //        this.load(null,xdata,{
20960 //                axis : "0 0 1 1",
20961 //                axisxlabels :  xdata
20962 //                });
20963
20964     },
20965
20966     load : function(graphtype,xdata,opts){
20967         this.raphael.clear();
20968         if(!graphtype) {
20969             graphtype = this.graphtype;
20970         }
20971         if(!opts){
20972             opts = this.opts;
20973         }
20974         var r = this.raphael,
20975             fin = function () {
20976                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
20977             },
20978             fout = function () {
20979                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
20980             },
20981             pfin = function() {
20982                 this.sector.stop();
20983                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
20984
20985                 if (this.label) {
20986                     this.label[0].stop();
20987                     this.label[0].attr({ r: 7.5 });
20988                     this.label[1].attr({ "font-weight": 800 });
20989                 }
20990             },
20991             pfout = function() {
20992                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
20993
20994                 if (this.label) {
20995                     this.label[0].animate({ r: 5 }, 500, "bounce");
20996                     this.label[1].attr({ "font-weight": 400 });
20997                 }
20998             };
20999
21000         switch(graphtype){
21001             case 'bar':
21002                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21003                 break;
21004             case 'hbar':
21005                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21006                 break;
21007             case 'pie':
21008 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
21009 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21010 //            
21011                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21012                 
21013                 break;
21014
21015         }
21016         
21017         if(this.title){
21018             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21019         }
21020         
21021     },
21022     
21023     setTitle: function(o)
21024     {
21025         this.title = o;
21026     },
21027     
21028     initEvents: function() {
21029         
21030         if(!this.href){
21031             this.el.on('click', this.onClick, this);
21032         }
21033     },
21034     
21035     onClick : function(e)
21036     {
21037         Roo.log('img onclick');
21038         this.fireEvent('click', this, e);
21039     }
21040    
21041 });
21042
21043  
21044 /*
21045  * - LGPL
21046  *
21047  * numberBox
21048  * 
21049  */
21050 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21051
21052 /**
21053  * @class Roo.bootstrap.dash.NumberBox
21054  * @extends Roo.bootstrap.Component
21055  * Bootstrap NumberBox class
21056  * @cfg {String} headline Box headline
21057  * @cfg {String} content Box content
21058  * @cfg {String} icon Box icon
21059  * @cfg {String} footer Footer text
21060  * @cfg {String} fhref Footer href
21061  * 
21062  * @constructor
21063  * Create a new NumberBox
21064  * @param {Object} config The config object
21065  */
21066
21067
21068 Roo.bootstrap.dash.NumberBox = function(config){
21069     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21070     
21071 };
21072
21073 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
21074     
21075     headline : '',
21076     content : '',
21077     icon : '',
21078     footer : '',
21079     fhref : '',
21080     ficon : '',
21081     
21082     getAutoCreate : function(){
21083         
21084         var cfg = {
21085             tag : 'div',
21086             cls : 'small-box ',
21087             cn : [
21088                 {
21089                     tag : 'div',
21090                     cls : 'inner',
21091                     cn :[
21092                         {
21093                             tag : 'h3',
21094                             cls : 'roo-headline',
21095                             html : this.headline
21096                         },
21097                         {
21098                             tag : 'p',
21099                             cls : 'roo-content',
21100                             html : this.content
21101                         }
21102                     ]
21103                 }
21104             ]
21105         }
21106         
21107         if(this.icon){
21108             cfg.cn.push({
21109                 tag : 'div',
21110                 cls : 'icon',
21111                 cn :[
21112                     {
21113                         tag : 'i',
21114                         cls : 'ion ' + this.icon
21115                     }
21116                 ]
21117             });
21118         }
21119         
21120         if(this.footer){
21121             var footer = {
21122                 tag : 'a',
21123                 cls : 'small-box-footer',
21124                 href : this.fhref || '#',
21125                 html : this.footer
21126             };
21127             
21128             cfg.cn.push(footer);
21129             
21130         }
21131         
21132         return  cfg;
21133     },
21134
21135     onRender : function(ct,position){
21136         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21137
21138
21139        
21140                 
21141     },
21142
21143     setHeadline: function (value)
21144     {
21145         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21146     },
21147     
21148     setFooter: function (value, href)
21149     {
21150         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21151         
21152         if(href){
21153             this.el.select('a.small-box-footer',true).first().attr('href', href);
21154         }
21155         
21156     },
21157
21158     setContent: function (value)
21159     {
21160         this.el.select('.roo-content',true).first().dom.innerHTML = value;
21161     },
21162
21163     initEvents: function() 
21164     {   
21165         
21166     }
21167     
21168 });
21169
21170  
21171 /*
21172  * - LGPL
21173  *
21174  * TabBox
21175  * 
21176  */
21177 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21178
21179 /**
21180  * @class Roo.bootstrap.dash.TabBox
21181  * @extends Roo.bootstrap.Component
21182  * Bootstrap TabBox class
21183  * @cfg {String} title Title of the TabBox
21184  * @cfg {String} icon Icon of the TabBox
21185  * @cfg {Boolean} showtabs (true|false) show the tabs default true
21186  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21187  * 
21188  * @constructor
21189  * Create a new TabBox
21190  * @param {Object} config The config object
21191  */
21192
21193
21194 Roo.bootstrap.dash.TabBox = function(config){
21195     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21196     this.addEvents({
21197         // raw events
21198         /**
21199          * @event addpane
21200          * When a pane is added
21201          * @param {Roo.bootstrap.dash.TabPane} pane
21202          */
21203         "addpane" : true,
21204         /**
21205          * @event activatepane
21206          * When a pane is activated
21207          * @param {Roo.bootstrap.dash.TabPane} pane
21208          */
21209         "activatepane" : true
21210         
21211          
21212     });
21213     
21214     this.panes = [];
21215 };
21216
21217 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
21218
21219     title : '',
21220     icon : false,
21221     showtabs : true,
21222     tabScrollable : false,
21223     
21224     getChildContainer : function()
21225     {
21226         return this.el.select('.tab-content', true).first();
21227     },
21228     
21229     getAutoCreate : function(){
21230         
21231         var header = {
21232             tag: 'li',
21233             cls: 'pull-left header',
21234             html: this.title,
21235             cn : []
21236         };
21237         
21238         if(this.icon){
21239             header.cn.push({
21240                 tag: 'i',
21241                 cls: 'fa ' + this.icon
21242             });
21243         }
21244         
21245         var h = {
21246             tag: 'ul',
21247             cls: 'nav nav-tabs pull-right',
21248             cn: [
21249                 header
21250             ]
21251         };
21252         
21253         if(this.tabScrollable){
21254             h = {
21255                 tag: 'div',
21256                 cls: 'tab-header',
21257                 cn: [
21258                     {
21259                         tag: 'ul',
21260                         cls: 'nav nav-tabs pull-right',
21261                         cn: [
21262                             header
21263                         ]
21264                     }
21265                 ]
21266             }
21267         }
21268         
21269         var cfg = {
21270             tag: 'div',
21271             cls: 'nav-tabs-custom',
21272             cn: [
21273                 h,
21274                 {
21275                     tag: 'div',
21276                     cls: 'tab-content no-padding',
21277                     cn: []
21278                 }
21279             ]
21280         }
21281
21282         return  cfg;
21283     },
21284     initEvents : function()
21285     {
21286         //Roo.log('add add pane handler');
21287         this.on('addpane', this.onAddPane, this);
21288     },
21289      /**
21290      * Updates the box title
21291      * @param {String} html to set the title to.
21292      */
21293     setTitle : function(value)
21294     {
21295         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21296     },
21297     onAddPane : function(pane)
21298     {
21299         this.panes.push(pane);
21300         //Roo.log('addpane');
21301         //Roo.log(pane);
21302         // tabs are rendere left to right..
21303         if(!this.showtabs){
21304             return;
21305         }
21306         
21307         var ctr = this.el.select('.nav-tabs', true).first();
21308          
21309          
21310         var existing = ctr.select('.nav-tab',true);
21311         var qty = existing.getCount();;
21312         
21313         
21314         var tab = ctr.createChild({
21315             tag : 'li',
21316             cls : 'nav-tab' + (qty ? '' : ' active'),
21317             cn : [
21318                 {
21319                     tag : 'a',
21320                     href:'#',
21321                     html : pane.title
21322                 }
21323             ]
21324         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21325         pane.tab = tab;
21326         
21327         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21328         if (!qty) {
21329             pane.el.addClass('active');
21330         }
21331         
21332                 
21333     },
21334     onTabClick : function(ev,un,ob,pane)
21335     {
21336         //Roo.log('tab - prev default');
21337         ev.preventDefault();
21338         
21339         
21340         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21341         pane.tab.addClass('active');
21342         //Roo.log(pane.title);
21343         this.getChildContainer().select('.tab-pane',true).removeClass('active');
21344         // technically we should have a deactivate event.. but maybe add later.
21345         // and it should not de-activate the selected tab...
21346         this.fireEvent('activatepane', pane);
21347         pane.el.addClass('active');
21348         pane.fireEvent('activate');
21349         
21350         
21351     },
21352     
21353     getActivePane : function()
21354     {
21355         var r = false;
21356         Roo.each(this.panes, function(p) {
21357             if(p.el.hasClass('active')){
21358                 r = p;
21359                 return false;
21360             }
21361             
21362             return;
21363         });
21364         
21365         return r;
21366     }
21367     
21368     
21369 });
21370
21371  
21372 /*
21373  * - LGPL
21374  *
21375  * Tab pane
21376  * 
21377  */
21378 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21379 /**
21380  * @class Roo.bootstrap.TabPane
21381  * @extends Roo.bootstrap.Component
21382  * Bootstrap TabPane class
21383  * @cfg {Boolean} active (false | true) Default false
21384  * @cfg {String} title title of panel
21385
21386  * 
21387  * @constructor
21388  * Create a new TabPane
21389  * @param {Object} config The config object
21390  */
21391
21392 Roo.bootstrap.dash.TabPane = function(config){
21393     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21394     
21395     this.addEvents({
21396         // raw events
21397         /**
21398          * @event activate
21399          * When a pane is activated
21400          * @param {Roo.bootstrap.dash.TabPane} pane
21401          */
21402         "activate" : true
21403          
21404     });
21405 };
21406
21407 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
21408     
21409     active : false,
21410     title : '',
21411     
21412     // the tabBox that this is attached to.
21413     tab : false,
21414      
21415     getAutoCreate : function() 
21416     {
21417         var cfg = {
21418             tag: 'div',
21419             cls: 'tab-pane'
21420         }
21421         
21422         if(this.active){
21423             cfg.cls += ' active';
21424         }
21425         
21426         return cfg;
21427     },
21428     initEvents  : function()
21429     {
21430         //Roo.log('trigger add pane handler');
21431         this.parent().fireEvent('addpane', this)
21432     },
21433     
21434      /**
21435      * Updates the tab title 
21436      * @param {String} html to set the title to.
21437      */
21438     setTitle: function(str)
21439     {
21440         if (!this.tab) {
21441             return;
21442         }
21443         this.title = str;
21444         this.tab.select('a', true).first().dom.innerHTML = str;
21445         
21446     }
21447     
21448     
21449     
21450 });
21451
21452  
21453
21454
21455  /*
21456  * - LGPL
21457  *
21458  * menu
21459  * 
21460  */
21461 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21462
21463 /**
21464  * @class Roo.bootstrap.menu.Menu
21465  * @extends Roo.bootstrap.Component
21466  * Bootstrap Menu class - container for Menu
21467  * @cfg {String} html Text of the menu
21468  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21469  * @cfg {String} icon Font awesome icon
21470  * @cfg {String} pos Menu align to (top | bottom) default bottom
21471  * 
21472  * 
21473  * @constructor
21474  * Create a new Menu
21475  * @param {Object} config The config object
21476  */
21477
21478
21479 Roo.bootstrap.menu.Menu = function(config){
21480     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21481     
21482     this.addEvents({
21483         /**
21484          * @event beforeshow
21485          * Fires before this menu is displayed
21486          * @param {Roo.bootstrap.menu.Menu} this
21487          */
21488         beforeshow : true,
21489         /**
21490          * @event beforehide
21491          * Fires before this menu is hidden
21492          * @param {Roo.bootstrap.menu.Menu} this
21493          */
21494         beforehide : true,
21495         /**
21496          * @event show
21497          * Fires after this menu is displayed
21498          * @param {Roo.bootstrap.menu.Menu} this
21499          */
21500         show : true,
21501         /**
21502          * @event hide
21503          * Fires after this menu is hidden
21504          * @param {Roo.bootstrap.menu.Menu} this
21505          */
21506         hide : true,
21507         /**
21508          * @event click
21509          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21510          * @param {Roo.bootstrap.menu.Menu} this
21511          * @param {Roo.EventObject} e
21512          */
21513         click : true
21514     });
21515     
21516 };
21517
21518 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
21519     
21520     submenu : false,
21521     html : '',
21522     weight : 'default',
21523     icon : false,
21524     pos : 'bottom',
21525     
21526     
21527     getChildContainer : function() {
21528         if(this.isSubMenu){
21529             return this.el;
21530         }
21531         
21532         return this.el.select('ul.dropdown-menu', true).first();  
21533     },
21534     
21535     getAutoCreate : function()
21536     {
21537         var text = [
21538             {
21539                 tag : 'span',
21540                 cls : 'roo-menu-text',
21541                 html : this.html
21542             }
21543         ];
21544         
21545         if(this.icon){
21546             text.unshift({
21547                 tag : 'i',
21548                 cls : 'fa ' + this.icon
21549             })
21550         }
21551         
21552         
21553         var cfg = {
21554             tag : 'div',
21555             cls : 'btn-group',
21556             cn : [
21557                 {
21558                     tag : 'button',
21559                     cls : 'dropdown-button btn btn-' + this.weight,
21560                     cn : text
21561                 },
21562                 {
21563                     tag : 'button',
21564                     cls : 'dropdown-toggle btn btn-' + this.weight,
21565                     cn : [
21566                         {
21567                             tag : 'span',
21568                             cls : 'caret'
21569                         }
21570                     ]
21571                 },
21572                 {
21573                     tag : 'ul',
21574                     cls : 'dropdown-menu'
21575                 }
21576             ]
21577             
21578         };
21579         
21580         if(this.pos == 'top'){
21581             cfg.cls += ' dropup';
21582         }
21583         
21584         if(this.isSubMenu){
21585             cfg = {
21586                 tag : 'ul',
21587                 cls : 'dropdown-menu'
21588             }
21589         }
21590         
21591         return cfg;
21592     },
21593     
21594     onRender : function(ct, position)
21595     {
21596         this.isSubMenu = ct.hasClass('dropdown-submenu');
21597         
21598         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21599     },
21600     
21601     initEvents : function() 
21602     {
21603         if(this.isSubMenu){
21604             return;
21605         }
21606         
21607         this.hidden = true;
21608         
21609         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21610         this.triggerEl.on('click', this.onTriggerPress, this);
21611         
21612         this.buttonEl = this.el.select('button.dropdown-button', true).first();
21613         this.buttonEl.on('click', this.onClick, this);
21614         
21615     },
21616     
21617     list : function()
21618     {
21619         if(this.isSubMenu){
21620             return this.el;
21621         }
21622         
21623         return this.el.select('ul.dropdown-menu', true).first();
21624     },
21625     
21626     onClick : function(e)
21627     {
21628         this.fireEvent("click", this, e);
21629     },
21630     
21631     onTriggerPress  : function(e)
21632     {   
21633         if (this.isVisible()) {
21634             this.hide();
21635         } else {
21636             this.show();
21637         }
21638     },
21639     
21640     isVisible : function(){
21641         return !this.hidden;
21642     },
21643     
21644     show : function()
21645     {
21646         this.fireEvent("beforeshow", this);
21647         
21648         this.hidden = false;
21649         this.el.addClass('open');
21650         
21651         Roo.get(document).on("mouseup", this.onMouseUp, this);
21652         
21653         this.fireEvent("show", this);
21654         
21655         
21656     },
21657     
21658     hide : function()
21659     {
21660         this.fireEvent("beforehide", this);
21661         
21662         this.hidden = true;
21663         this.el.removeClass('open');
21664         
21665         Roo.get(document).un("mouseup", this.onMouseUp);
21666         
21667         this.fireEvent("hide", this);
21668     },
21669     
21670     onMouseUp : function()
21671     {
21672         this.hide();
21673     }
21674     
21675 });
21676
21677  
21678  /*
21679  * - LGPL
21680  *
21681  * menu item
21682  * 
21683  */
21684 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21685
21686 /**
21687  * @class Roo.bootstrap.menu.Item
21688  * @extends Roo.bootstrap.Component
21689  * Bootstrap MenuItem class
21690  * @cfg {Boolean} submenu (true | false) default false
21691  * @cfg {String} html text of the item
21692  * @cfg {String} href the link
21693  * @cfg {Boolean} disable (true | false) default false
21694  * @cfg {Boolean} preventDefault (true | false) default true
21695  * @cfg {String} icon Font awesome icon
21696  * @cfg {String} pos Submenu align to (left | right) default right 
21697  * 
21698  * 
21699  * @constructor
21700  * Create a new Item
21701  * @param {Object} config The config object
21702  */
21703
21704
21705 Roo.bootstrap.menu.Item = function(config){
21706     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
21707     this.addEvents({
21708         /**
21709          * @event mouseover
21710          * Fires when the mouse is hovering over this menu
21711          * @param {Roo.bootstrap.menu.Item} this
21712          * @param {Roo.EventObject} e
21713          */
21714         mouseover : true,
21715         /**
21716          * @event mouseout
21717          * Fires when the mouse exits this menu
21718          * @param {Roo.bootstrap.menu.Item} this
21719          * @param {Roo.EventObject} e
21720          */
21721         mouseout : true,
21722         // raw events
21723         /**
21724          * @event click
21725          * The raw click event for the entire grid.
21726          * @param {Roo.EventObject} e
21727          */
21728         click : true
21729     });
21730 };
21731
21732 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
21733     
21734     submenu : false,
21735     href : '',
21736     html : '',
21737     preventDefault: true,
21738     disable : false,
21739     icon : false,
21740     pos : 'right',
21741     
21742     getAutoCreate : function()
21743     {
21744         var text = [
21745             {
21746                 tag : 'span',
21747                 cls : 'roo-menu-item-text',
21748                 html : this.html
21749             }
21750         ];
21751         
21752         if(this.icon){
21753             text.unshift({
21754                 tag : 'i',
21755                 cls : 'fa ' + this.icon
21756             })
21757         }
21758         
21759         var cfg = {
21760             tag : 'li',
21761             cn : [
21762                 {
21763                     tag : 'a',
21764                     href : this.href || '#',
21765                     cn : text
21766                 }
21767             ]
21768         };
21769         
21770         if(this.disable){
21771             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
21772         }
21773         
21774         if(this.submenu){
21775             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
21776             
21777             if(this.pos == 'left'){
21778                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
21779             }
21780         }
21781         
21782         return cfg;
21783     },
21784     
21785     initEvents : function() 
21786     {
21787         this.el.on('mouseover', this.onMouseOver, this);
21788         this.el.on('mouseout', this.onMouseOut, this);
21789         
21790         this.el.select('a', true).first().on('click', this.onClick, this);
21791         
21792     },
21793     
21794     onClick : function(e)
21795     {
21796         if(this.preventDefault){
21797             e.preventDefault();
21798         }
21799         
21800         this.fireEvent("click", this, e);
21801     },
21802     
21803     onMouseOver : function(e)
21804     {
21805         if(this.submenu && this.pos == 'left'){
21806             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
21807         }
21808         
21809         this.fireEvent("mouseover", this, e);
21810     },
21811     
21812     onMouseOut : function(e)
21813     {
21814         this.fireEvent("mouseout", this, e);
21815     }
21816 });
21817
21818  
21819
21820  /*
21821  * - LGPL
21822  *
21823  * menu separator
21824  * 
21825  */
21826 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21827
21828 /**
21829  * @class Roo.bootstrap.menu.Separator
21830  * @extends Roo.bootstrap.Component
21831  * Bootstrap Separator class
21832  * 
21833  * @constructor
21834  * Create a new Separator
21835  * @param {Object} config The config object
21836  */
21837
21838
21839 Roo.bootstrap.menu.Separator = function(config){
21840     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
21841 };
21842
21843 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
21844     
21845     getAutoCreate : function(){
21846         var cfg = {
21847             tag : 'li',
21848             cls: 'divider'
21849         };
21850         
21851         return cfg;
21852     }
21853    
21854 });
21855
21856  
21857
21858  /*
21859  * - LGPL
21860  *
21861  * Tooltip
21862  * 
21863  */
21864
21865 /**
21866  * @class Roo.bootstrap.Tooltip
21867  * Bootstrap Tooltip class
21868  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
21869  * to determine which dom element triggers the tooltip.
21870  * 
21871  * It needs to add support for additional attributes like tooltip-position
21872  * 
21873  * @constructor
21874  * Create a new Toolti
21875  * @param {Object} config The config object
21876  */
21877
21878 Roo.bootstrap.Tooltip = function(config){
21879     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
21880 };
21881
21882 Roo.apply(Roo.bootstrap.Tooltip, {
21883     /**
21884      * @function init initialize tooltip monitoring.
21885      * @static
21886      */
21887     currentEl : false,
21888     currentTip : false,
21889     currentRegion : false,
21890     
21891     //  init : delay?
21892     
21893     init : function()
21894     {
21895         Roo.get(document).on('mouseover', this.enter ,this);
21896         Roo.get(document).on('mouseout', this.leave, this);
21897          
21898         
21899         this.currentTip = new Roo.bootstrap.Tooltip();
21900     },
21901     
21902     enter : function(ev)
21903     {
21904         var dom = ev.getTarget();
21905         
21906         //Roo.log(['enter',dom]);
21907         var el = Roo.fly(dom);
21908         if (this.currentEl) {
21909             //Roo.log(dom);
21910             //Roo.log(this.currentEl);
21911             //Roo.log(this.currentEl.contains(dom));
21912             if (this.currentEl == el) {
21913                 return;
21914             }
21915             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
21916                 return;
21917             }
21918
21919         }
21920         
21921         
21922         
21923         if (this.currentTip.el) {
21924             this.currentTip.el.hide(); // force hiding...
21925         }    
21926         //Roo.log(ev);
21927         var bindEl = el;
21928         
21929         // you can not look for children, as if el is the body.. then everythign is the child..
21930         if (!el.attr('tooltip')) { //
21931             if (!el.select("[tooltip]").elements.length) {
21932                 return;
21933             }
21934             // is the mouse over this child...?
21935             bindEl = el.select("[tooltip]").first();
21936             var xy = ev.getXY();
21937             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
21938                 //Roo.log("not in region.");
21939                 return;
21940             }
21941             //Roo.log("child element over..");
21942             
21943         }
21944         this.currentEl = bindEl;
21945         this.currentTip.bind(bindEl);
21946         this.currentRegion = Roo.lib.Region.getRegion(dom);
21947         this.currentTip.enter();
21948         
21949     },
21950     leave : function(ev)
21951     {
21952         var dom = ev.getTarget();
21953         //Roo.log(['leave',dom]);
21954         if (!this.currentEl) {
21955             return;
21956         }
21957         
21958         
21959         if (dom != this.currentEl.dom) {
21960             return;
21961         }
21962         var xy = ev.getXY();
21963         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
21964             return;
21965         }
21966         // only activate leave if mouse cursor is outside... bounding box..
21967         
21968         
21969         
21970         
21971         if (this.currentTip) {
21972             this.currentTip.leave();
21973         }
21974         //Roo.log('clear currentEl');
21975         this.currentEl = false;
21976         
21977         
21978     },
21979     alignment : {
21980         'left' : ['r-l', [-2,0], 'right'],
21981         'right' : ['l-r', [2,0], 'left'],
21982         'bottom' : ['t-b', [0,2], 'top'],
21983         'top' : [ 'b-t', [0,-2], 'bottom']
21984     }
21985     
21986 });
21987
21988
21989 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
21990     
21991     
21992     bindEl : false,
21993     
21994     delay : null, // can be { show : 300 , hide: 500}
21995     
21996     timeout : null,
21997     
21998     hoverState : null, //???
21999     
22000     placement : 'bottom', 
22001     
22002     getAutoCreate : function(){
22003     
22004         var cfg = {
22005            cls : 'tooltip',
22006            role : 'tooltip',
22007            cn : [
22008                 {
22009                     cls : 'tooltip-arrow'
22010                 },
22011                 {
22012                     cls : 'tooltip-inner'
22013                 }
22014            ]
22015         };
22016         
22017         return cfg;
22018     },
22019     bind : function(el)
22020     {
22021         this.bindEl = el;
22022     },
22023       
22024     
22025     enter : function () {
22026        
22027         if (this.timeout != null) {
22028             clearTimeout(this.timeout);
22029         }
22030         
22031         this.hoverState = 'in';
22032          //Roo.log("enter - show");
22033         if (!this.delay || !this.delay.show) {
22034             this.show();
22035             return;
22036         }
22037         var _t = this;
22038         this.timeout = setTimeout(function () {
22039             if (_t.hoverState == 'in') {
22040                 _t.show();
22041             }
22042         }, this.delay.show);
22043     },
22044     leave : function()
22045     {
22046         clearTimeout(this.timeout);
22047     
22048         this.hoverState = 'out';
22049          if (!this.delay || !this.delay.hide) {
22050             this.hide();
22051             return;
22052         }
22053        
22054         var _t = this;
22055         this.timeout = setTimeout(function () {
22056             //Roo.log("leave - timeout");
22057             
22058             if (_t.hoverState == 'out') {
22059                 _t.hide();
22060                 Roo.bootstrap.Tooltip.currentEl = false;
22061             }
22062         }, delay);
22063     },
22064     
22065     show : function ()
22066     {
22067         if (!this.el) {
22068             this.render(document.body);
22069         }
22070         // set content.
22071         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22072         
22073         var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22074         
22075         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22076         
22077         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22078         
22079         var placement = typeof this.placement == 'function' ?
22080             this.placement.call(this, this.el, on_el) :
22081             this.placement;
22082             
22083         var autoToken = /\s?auto?\s?/i;
22084         var autoPlace = autoToken.test(placement);
22085         if (autoPlace) {
22086             placement = placement.replace(autoToken, '') || 'top';
22087         }
22088         
22089         //this.el.detach()
22090         //this.el.setXY([0,0]);
22091         this.el.show();
22092         //this.el.dom.style.display='block';
22093         this.el.addClass(placement);
22094         
22095         //this.el.appendTo(on_el);
22096         
22097         var p = this.getPosition();
22098         var box = this.el.getBox();
22099         
22100         if (autoPlace) {
22101             // fixme..
22102         }
22103         var align = Roo.bootstrap.Tooltip.alignment[placement];
22104         this.el.alignTo(this.bindEl, align[0],align[1]);
22105         //var arrow = this.el.select('.arrow',true).first();
22106         //arrow.set(align[2], 
22107         
22108         this.el.addClass('in fade');
22109         this.hoverState = null;
22110         
22111         if (this.el.hasClass('fade')) {
22112             // fade it?
22113         }
22114         
22115     },
22116     hide : function()
22117     {
22118          
22119         if (!this.el) {
22120             return;
22121         }
22122         //this.el.setXY([0,0]);
22123         this.el.removeClass('in');
22124         //this.el.hide();
22125         
22126     }
22127     
22128 });
22129  
22130
22131  /*
22132  * - LGPL
22133  *
22134  * Location Picker
22135  * 
22136  */
22137
22138 /**
22139  * @class Roo.bootstrap.LocationPicker
22140  * @extends Roo.bootstrap.Component
22141  * Bootstrap LocationPicker class
22142  * @cfg {Number} latitude Position when init default 0
22143  * @cfg {Number} longitude Position when init default 0
22144  * @cfg {Number} zoom default 15
22145  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22146  * @cfg {Boolean} mapTypeControl default false
22147  * @cfg {Boolean} disableDoubleClickZoom default false
22148  * @cfg {Boolean} scrollwheel default true
22149  * @cfg {Boolean} streetViewControl default false
22150  * @cfg {Number} radius default 0
22151  * @cfg {String} locationName
22152  * @cfg {Boolean} draggable default true
22153  * @cfg {Boolean} enableAutocomplete default false
22154  * @cfg {Boolean} enableReverseGeocode default true
22155  * @cfg {String} markerTitle
22156  * 
22157  * @constructor
22158  * Create a new LocationPicker
22159  * @param {Object} config The config object
22160  */
22161
22162
22163 Roo.bootstrap.LocationPicker = function(config){
22164     
22165     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22166     
22167     this.addEvents({
22168         /**
22169          * @event initial
22170          * Fires when the picker initialized.
22171          * @param {Roo.bootstrap.LocationPicker} this
22172          * @param {Google Location} location
22173          */
22174         initial : true,
22175         /**
22176          * @event positionchanged
22177          * Fires when the picker position changed.
22178          * @param {Roo.bootstrap.LocationPicker} this
22179          * @param {Google Location} location
22180          */
22181         positionchanged : true,
22182         /**
22183          * @event resize
22184          * Fires when the map resize.
22185          * @param {Roo.bootstrap.LocationPicker} this
22186          */
22187         resize : true,
22188         /**
22189          * @event show
22190          * Fires when the map show.
22191          * @param {Roo.bootstrap.LocationPicker} this
22192          */
22193         show : true,
22194         /**
22195          * @event hide
22196          * Fires when the map hide.
22197          * @param {Roo.bootstrap.LocationPicker} this
22198          */
22199         hide : true,
22200         /**
22201          * @event mapClick
22202          * Fires when click the map.
22203          * @param {Roo.bootstrap.LocationPicker} this
22204          * @param {Map event} e
22205          */
22206         mapClick : true,
22207         /**
22208          * @event mapRightClick
22209          * Fires when right click the map.
22210          * @param {Roo.bootstrap.LocationPicker} this
22211          * @param {Map event} e
22212          */
22213         mapRightClick : true,
22214         /**
22215          * @event markerClick
22216          * Fires when click the marker.
22217          * @param {Roo.bootstrap.LocationPicker} this
22218          * @param {Map event} e
22219          */
22220         markerClick : true,
22221         /**
22222          * @event markerRightClick
22223          * Fires when right click the marker.
22224          * @param {Roo.bootstrap.LocationPicker} this
22225          * @param {Map event} e
22226          */
22227         markerRightClick : true,
22228         /**
22229          * @event OverlayViewDraw
22230          * Fires when OverlayView Draw
22231          * @param {Roo.bootstrap.LocationPicker} this
22232          */
22233         OverlayViewDraw : true,
22234         /**
22235          * @event OverlayViewOnAdd
22236          * Fires when OverlayView Draw
22237          * @param {Roo.bootstrap.LocationPicker} this
22238          */
22239         OverlayViewOnAdd : true,
22240         /**
22241          * @event OverlayViewOnRemove
22242          * Fires when OverlayView Draw
22243          * @param {Roo.bootstrap.LocationPicker} this
22244          */
22245         OverlayViewOnRemove : true,
22246         /**
22247          * @event OverlayViewShow
22248          * Fires when OverlayView Draw
22249          * @param {Roo.bootstrap.LocationPicker} this
22250          * @param {Pixel} cpx
22251          */
22252         OverlayViewShow : true,
22253         /**
22254          * @event OverlayViewHide
22255          * Fires when OverlayView Draw
22256          * @param {Roo.bootstrap.LocationPicker} this
22257          */
22258         OverlayViewHide : true
22259     });
22260         
22261 };
22262
22263 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
22264     
22265     gMapContext: false,
22266     
22267     latitude: 0,
22268     longitude: 0,
22269     zoom: 15,
22270     mapTypeId: false,
22271     mapTypeControl: false,
22272     disableDoubleClickZoom: false,
22273     scrollwheel: true,
22274     streetViewControl: false,
22275     radius: 0,
22276     locationName: '',
22277     draggable: true,
22278     enableAutocomplete: false,
22279     enableReverseGeocode: true,
22280     markerTitle: '',
22281     
22282     getAutoCreate: function()
22283     {
22284
22285         var cfg = {
22286             tag: 'div',
22287             cls: 'roo-location-picker'
22288         };
22289         
22290         return cfg
22291     },
22292     
22293     initEvents: function(ct, position)
22294     {       
22295         if(!this.el.getWidth() || this.isApplied()){
22296             return;
22297         }
22298         
22299         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22300         
22301         this.initial();
22302     },
22303     
22304     initial: function()
22305     {
22306         if(!this.mapTypeId){
22307             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22308         }
22309         
22310         this.gMapContext = this.GMapContext();
22311         
22312         this.initOverlayView();
22313         
22314         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22315         
22316         var _this = this;
22317                 
22318         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22319             _this.setPosition(_this.gMapContext.marker.position);
22320         });
22321         
22322         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22323             _this.fireEvent('mapClick', this, event);
22324             
22325         });
22326
22327         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22328             _this.fireEvent('mapRightClick', this, event);
22329             
22330         });
22331         
22332         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22333             _this.fireEvent('markerClick', this, event);
22334             
22335         });
22336
22337         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22338             _this.fireEvent('markerRightClick', this, event);
22339             
22340         });
22341         
22342         this.setPosition(this.gMapContext.location);
22343         
22344         this.fireEvent('initial', this, this.gMapContext.location);
22345     },
22346     
22347     initOverlayView: function()
22348     {
22349         var _this = this;
22350         
22351         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22352             
22353             draw: function()
22354             {
22355                 _this.fireEvent('OverlayViewDraw', _this);
22356             },
22357             
22358             onAdd: function()
22359             {
22360                 _this.fireEvent('OverlayViewOnAdd', _this);
22361             },
22362             
22363             onRemove: function()
22364             {
22365                 _this.fireEvent('OverlayViewOnRemove', _this);
22366             },
22367             
22368             show: function(cpx)
22369             {
22370                 _this.fireEvent('OverlayViewShow', _this, cpx);
22371             },
22372             
22373             hide: function()
22374             {
22375                 _this.fireEvent('OverlayViewHide', _this);
22376             }
22377             
22378         });
22379     },
22380     
22381     fromLatLngToContainerPixel: function(event)
22382     {
22383         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22384     },
22385     
22386     isApplied: function() 
22387     {
22388         return this.getGmapContext() == false ? false : true;
22389     },
22390     
22391     getGmapContext: function() 
22392     {
22393         return this.gMapContext
22394     },
22395     
22396     GMapContext: function() 
22397     {
22398         var position = new google.maps.LatLng(this.latitude, this.longitude);
22399         
22400         var _map = new google.maps.Map(this.el.dom, {
22401             center: position,
22402             zoom: this.zoom,
22403             mapTypeId: this.mapTypeId,
22404             mapTypeControl: this.mapTypeControl,
22405             disableDoubleClickZoom: this.disableDoubleClickZoom,
22406             scrollwheel: this.scrollwheel,
22407             streetViewControl: this.streetViewControl,
22408             locationName: this.locationName,
22409             draggable: this.draggable,
22410             enableAutocomplete: this.enableAutocomplete,
22411             enableReverseGeocode: this.enableReverseGeocode
22412         });
22413         
22414         var _marker = new google.maps.Marker({
22415             position: position,
22416             map: _map,
22417             title: this.markerTitle,
22418             draggable: this.draggable
22419         });
22420         
22421         return {
22422             map: _map,
22423             marker: _marker,
22424             circle: null,
22425             location: position,
22426             radius: this.radius,
22427             locationName: this.locationName,
22428             addressComponents: {
22429                 formatted_address: null,
22430                 addressLine1: null,
22431                 addressLine2: null,
22432                 streetName: null,
22433                 streetNumber: null,
22434                 city: null,
22435                 district: null,
22436                 state: null,
22437                 stateOrProvince: null
22438             },
22439             settings: this,
22440             domContainer: this.el.dom,
22441             geodecoder: new google.maps.Geocoder()
22442         };
22443     },
22444     
22445     drawCircle: function(center, radius, options) 
22446     {
22447         if (this.gMapContext.circle != null) {
22448             this.gMapContext.circle.setMap(null);
22449         }
22450         if (radius > 0) {
22451             radius *= 1;
22452             options = Roo.apply({}, options, {
22453                 strokeColor: "#0000FF",
22454                 strokeOpacity: .35,
22455                 strokeWeight: 2,
22456                 fillColor: "#0000FF",
22457                 fillOpacity: .2
22458             });
22459             
22460             options.map = this.gMapContext.map;
22461             options.radius = radius;
22462             options.center = center;
22463             this.gMapContext.circle = new google.maps.Circle(options);
22464             return this.gMapContext.circle;
22465         }
22466         
22467         return null;
22468     },
22469     
22470     setPosition: function(location) 
22471     {
22472         this.gMapContext.location = location;
22473         this.gMapContext.marker.setPosition(location);
22474         this.gMapContext.map.panTo(location);
22475         this.drawCircle(location, this.gMapContext.radius, {});
22476         
22477         var _this = this;
22478         
22479         if (this.gMapContext.settings.enableReverseGeocode) {
22480             this.gMapContext.geodecoder.geocode({
22481                 latLng: this.gMapContext.location
22482             }, function(results, status) {
22483                 
22484                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22485                     _this.gMapContext.locationName = results[0].formatted_address;
22486                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22487                     
22488                     _this.fireEvent('positionchanged', this, location);
22489                 }
22490             });
22491             
22492             return;
22493         }
22494         
22495         this.fireEvent('positionchanged', this, location);
22496     },
22497     
22498     resize: function()
22499     {
22500         google.maps.event.trigger(this.gMapContext.map, "resize");
22501         
22502         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22503         
22504         this.fireEvent('resize', this);
22505     },
22506     
22507     setPositionByLatLng: function(latitude, longitude)
22508     {
22509         this.setPosition(new google.maps.LatLng(latitude, longitude));
22510     },
22511     
22512     getCurrentPosition: function() 
22513     {
22514         return {
22515             latitude: this.gMapContext.location.lat(),
22516             longitude: this.gMapContext.location.lng()
22517         };
22518     },
22519     
22520     getAddressName: function() 
22521     {
22522         return this.gMapContext.locationName;
22523     },
22524     
22525     getAddressComponents: function() 
22526     {
22527         return this.gMapContext.addressComponents;
22528     },
22529     
22530     address_component_from_google_geocode: function(address_components) 
22531     {
22532         var result = {};
22533         
22534         for (var i = 0; i < address_components.length; i++) {
22535             var component = address_components[i];
22536             if (component.types.indexOf("postal_code") >= 0) {
22537                 result.postalCode = component.short_name;
22538             } else if (component.types.indexOf("street_number") >= 0) {
22539                 result.streetNumber = component.short_name;
22540             } else if (component.types.indexOf("route") >= 0) {
22541                 result.streetName = component.short_name;
22542             } else if (component.types.indexOf("neighborhood") >= 0) {
22543                 result.city = component.short_name;
22544             } else if (component.types.indexOf("locality") >= 0) {
22545                 result.city = component.short_name;
22546             } else if (component.types.indexOf("sublocality") >= 0) {
22547                 result.district = component.short_name;
22548             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22549                 result.stateOrProvince = component.short_name;
22550             } else if (component.types.indexOf("country") >= 0) {
22551                 result.country = component.short_name;
22552             }
22553         }
22554         
22555         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22556         result.addressLine2 = "";
22557         return result;
22558     },
22559     
22560     setZoomLevel: function(zoom)
22561     {
22562         this.gMapContext.map.setZoom(zoom);
22563     },
22564     
22565     show: function()
22566     {
22567         if(!this.el){
22568             return;
22569         }
22570         
22571         this.el.show();
22572         
22573         this.resize();
22574         
22575         this.fireEvent('show', this);
22576     },
22577     
22578     hide: function()
22579     {
22580         if(!this.el){
22581             return;
22582         }
22583         
22584         this.el.hide();
22585         
22586         this.fireEvent('hide', this);
22587     }
22588     
22589 });
22590
22591 Roo.apply(Roo.bootstrap.LocationPicker, {
22592     
22593     OverlayView : function(map, options)
22594     {
22595         options = options || {};
22596         
22597         this.setMap(map);
22598     }
22599     
22600     
22601 });/*
22602  * - LGPL
22603  *
22604  * Alert
22605  * 
22606  */
22607
22608 /**
22609  * @class Roo.bootstrap.Alert
22610  * @extends Roo.bootstrap.Component
22611  * Bootstrap Alert class
22612  * @cfg {String} title The title of alert
22613  * @cfg {String} html The content of alert
22614  * @cfg {String} weight (  success | info | warning | danger )
22615  * @cfg {String} faicon font-awesomeicon
22616  * 
22617  * @constructor
22618  * Create a new alert
22619  * @param {Object} config The config object
22620  */
22621
22622
22623 Roo.bootstrap.Alert = function(config){
22624     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22625     
22626 };
22627
22628 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
22629     
22630     title: '',
22631     html: '',
22632     weight: false,
22633     faicon: false,
22634     
22635     getAutoCreate : function()
22636     {
22637         
22638         var cfg = {
22639             tag : 'div',
22640             cls : 'alert',
22641             cn : [
22642                 {
22643                     tag : 'i',
22644                     cls : 'roo-alert-icon'
22645                     
22646                 },
22647                 {
22648                     tag : 'b',
22649                     cls : 'roo-alert-title',
22650                     html : this.title
22651                 },
22652                 {
22653                     tag : 'span',
22654                     cls : 'roo-alert-text',
22655                     html : this.html
22656                 }
22657             ]
22658         };
22659         
22660         if(this.faicon){
22661             cfg.cn[0].cls += ' fa ' + this.faicon;
22662         }
22663         
22664         if(this.weight){
22665             cfg.cls += ' alert-' + this.weight;
22666         }
22667         
22668         return cfg;
22669     },
22670     
22671     initEvents: function() 
22672     {
22673         this.el.setVisibilityMode(Roo.Element.DISPLAY);
22674     },
22675     
22676     setTitle : function(str)
22677     {
22678         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
22679     },
22680     
22681     setText : function(str)
22682     {
22683         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
22684     },
22685     
22686     setWeight : function(weight)
22687     {
22688         if(this.weight){
22689             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
22690         }
22691         
22692         this.weight = weight;
22693         
22694         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
22695     },
22696     
22697     setIcon : function(icon)
22698     {
22699         if(this.faicon){
22700             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
22701         }
22702         
22703         this.faicon = icon
22704         
22705         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
22706     },
22707     
22708     hide: function() 
22709     {
22710         this.el.hide();   
22711     },
22712     
22713     show: function() 
22714     {  
22715         this.el.show();   
22716     }
22717     
22718 });
22719
22720