less/roojs-bootstrap/checkbox.less
[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  * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
22  
23  * @constructor
24  * Do not use directly - it does not do anything..
25  * @param {Object} config The config object
26  */
27
28
29
30 Roo.bootstrap.Component = function(config){
31     Roo.bootstrap.Component.superclass.constructor.call(this, config);
32        
33     this.addEvents({
34         /**
35          * @event childrenrendered
36          * Fires when the children have been rendered..
37          * @param {Roo.bootstrap.Component} this
38          */
39         "childrenrendered" : true
40         
41         
42         
43     });
44     
45     
46 };
47
48 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
49     
50     
51     allowDomMove : false, // to stop relocations in parent onRender...
52     
53     cls : false,
54     
55     style : false,
56     
57     autoCreate : false,
58     
59     tooltip : null,
60     /**
61      * Initialize Events for the element
62      */
63     initEvents : function() { },
64     
65     xattr : false,
66     
67     parentId : false,
68     
69     can_build_overlaid : true,
70     
71     container_method : false,
72     
73     dataId : false,
74     
75     name : false,
76     
77     parent: function() {
78         // returns the parent component..
79         return Roo.ComponentMgr.get(this.parentId)
80         
81         
82     },
83     
84     // private
85     onRender : function(ct, position)
86     {
87        // Roo.log("Call onRender: " + this.xtype);
88         
89         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
90         
91         if(this.el){
92             if (this.el.attr('xtype')) {
93                 this.el.attr('xtypex', this.el.attr('xtype'));
94                 this.el.dom.removeAttribute('xtype');
95                 
96                 this.initEvents();
97             }
98             
99             return;
100         }
101         
102          
103         
104         var cfg = Roo.apply({},  this.getAutoCreate());
105         
106         cfg.id = this.id || Roo.id();
107         
108         // fill in the extra attributes 
109         if (this.xattr && typeof(this.xattr) =='object') {
110             for (var i in this.xattr) {
111                 cfg[i] = this.xattr[i];
112             }
113         }
114         
115         if(this.dataId){
116             cfg.dataId = this.dataId;
117         }
118         
119         if (this.cls) {
120             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
121         }
122         
123         if (this.style) { // fixme needs to support more complex style data.
124             cfg.style = this.style;
125         }
126         
127         if(this.name){
128             cfg.name = this.name;
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         
141         this.initEvents();
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         //Roo.log(['addxtype', cn]);
167            
168         cn.parentType = this.xtype; //??
169         cn.parentId = this.id;
170         
171         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172         if (typeof(cn.container_method) == 'string') {
173             cntr = cn.container_method;
174         }
175         
176         
177         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
178         
179         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
180         
181         var build_from_html =  Roo.XComponent.build_from_html;
182           
183         var is_body  = (tree.xtype == 'Body') ;
184           
185         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
186           
187         var self_cntr_el = Roo.get(this[cntr](false));
188         
189         // do not try and build conditional elements 
190         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
191             return false;
192         }
193         
194         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
195             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
196                 return this.addxtypeChild(tree,cntr, is_body);
197             }
198             
199             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
200                 
201             if(echild){
202                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
203             }
204             
205             Roo.log('skipping render');
206             return cn;
207             
208         }
209         
210         var ret = false;
211         if (!build_from_html) {
212             return false;
213         }
214         
215         // this i think handles overlaying multiple children of the same type
216         // with the sam eelement.. - which might be buggy..
217         while (true) {
218             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
219             
220             if (!echild) {
221                 break;
222             }
223             
224             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
225                 break;
226             }
227             
228             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
229         }
230        
231         return ret;
232     },
233     
234     
235     addxtypeChild : function (tree, cntr, is_body)
236     {
237         Roo.debug && Roo.log('addxtypeChild:' + cntr);
238         var cn = this;
239         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
240         
241         
242         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
243                     (typeof(tree['flexy:foreach']) != 'undefined');
244           
245     
246         
247         skip_children = false;
248         // render the element if it's not BODY.
249         if (!is_body) {
250             
251             // if parent was disabled, then do not try and create the children..
252             if(!this[cntr](true)){
253                 tree.items = [];
254                 return tree;
255             }
256            
257             cn = Roo.factory(tree);
258            
259             cn.parentType = this.xtype; //??
260             cn.parentId = this.id;
261             
262             var build_from_html =  Roo.XComponent.build_from_html;
263             
264             
265             // does the container contain child eleemnts with 'xtype' attributes.
266             // that match this xtype..
267             // note - when we render we create these as well..
268             // so we should check to see if body has xtype set.
269             if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
270                
271                 var self_cntr_el = Roo.get(this[cntr](false));
272                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
273                 if (echild) { 
274                     //Roo.log(Roo.XComponent.build_from_html);
275                     //Roo.log("got echild:");
276                     //Roo.log(echild);
277                 }
278                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
279                 // and are not displayed -this causes this to use up the wrong element when matching.
280                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
281                 
282                 
283                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
284                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
285                   
286                   
287                   
288                     cn.el = echild;
289                   //  Roo.log("GOT");
290                     //echild.dom.removeAttribute('xtype');
291                 } else {
292                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
293                     Roo.debug && Roo.log(self_cntr_el);
294                     Roo.debug && Roo.log(echild);
295                     Roo.debug && Roo.log(cn);
296                 }
297             }
298            
299             
300            
301             // if object has flexy:if - then it may or may not be rendered.
302             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
303                 // skip a flexy if element.
304                 Roo.debug && Roo.log('skipping render');
305                 Roo.debug && Roo.log(tree);
306                 if (!cn.el) {
307                     Roo.debug && Roo.log('skipping all children');
308                     skip_children = true;
309                 }
310                 
311              } else {
312                  
313                 // actually if flexy:foreach is found, we really want to create 
314                 // multiple copies here...
315                 //Roo.log('render');
316                 //Roo.log(this[cntr]());
317                 // some elements do not have render methods.. like the layouts...
318                 /*
319                 if(this[cntr](true) === false){
320                     cn.items = [];
321                     return cn;
322                 }
323                 */
324                 cn.render && cn.render(this[cntr](true));
325                 
326              }
327             // then add the element..
328         }
329          
330         // handle the kids..
331         
332         var nitems = [];
333         /*
334         if (typeof (tree.menu) != 'undefined') {
335             tree.menu.parentType = cn.xtype;
336             tree.menu.triggerEl = cn.el;
337             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
338             
339         }
340         */
341         if (!tree.items || !tree.items.length) {
342             cn.items = nitems;
343             //Roo.log(["no children", this]);
344             
345             return cn;
346         }
347          
348         var items = tree.items;
349         delete tree.items;
350         
351         //Roo.log(items.length);
352             // add the items..
353         if (!skip_children) {    
354             for(var i =0;i < items.length;i++) {
355               //  Roo.log(['add child', items[i]]);
356                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
357             }
358         }
359         
360         cn.items = nitems;
361         
362         //Roo.log("fire childrenrendered");
363         
364         cn.fireEvent('childrenrendered', this);
365         
366         return cn;
367     },
368     
369     /**
370      * Set the element that will be used to show or hide
371      */
372     setVisibilityEl : function(el)
373     {
374         this.visibilityEl = el;
375     },
376     
377      /**
378      * Get the element that will be used to show or hide
379      */
380     getVisibilityEl : function()
381     {
382         if (typeof(this.visibilityEl) == 'object') {
383             return this.visibilityEl;
384         }
385         
386         if (typeof(this.visibilityEl) == 'string') {
387             return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
388         }
389         
390         return this.getEl();
391     },
392     
393     /**
394      * Show a component - removes 'hidden' class
395      */
396     show : function()
397     {
398         if(!this.getVisibilityEl()){
399             return;
400         }
401          
402         this.getVisibilityEl().removeClass('hidden');
403         
404         this.fireEvent('show', this);
405         
406         
407     },
408     /**
409      * Hide a component - adds 'hidden' class
410      */
411     hide: function()
412     {
413         if(!this.getVisibilityEl()){
414             return;
415         }
416         
417         this.getVisibilityEl().addClass('hidden');
418         
419         this.fireEvent('hide', this);
420         
421     }
422 });
423
424  /*
425  * - LGPL
426  *
427  * Body
428  *
429  */
430
431 /**
432  * @class Roo.bootstrap.Body
433  * @extends Roo.bootstrap.Component
434  * Bootstrap Body class
435  *
436  * @constructor
437  * Create a new body
438  * @param {Object} config The config object
439  */
440
441 Roo.bootstrap.Body = function(config){
442
443     config = config || {};
444
445     Roo.bootstrap.Body.superclass.constructor.call(this, config);
446     this.el = Roo.get(config.el ? config.el : document.body );
447     if (this.cls && this.cls.length) {
448         Roo.get(document.body).addClass(this.cls);
449     }
450 };
451
452 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
453
454     is_body : true,// just to make sure it's constructed?
455
456         autoCreate : {
457         cls: 'container'
458     },
459     onRender : function(ct, position)
460     {
461        /* Roo.log("Roo.bootstrap.Body - onRender");
462         if (this.cls && this.cls.length) {
463             Roo.get(document.body).addClass(this.cls);
464         }
465         // style??? xttr???
466         */
467     }
468
469
470
471
472 });
473 /*
474  * - LGPL
475  *
476  * button group
477  * 
478  */
479
480
481 /**
482  * @class Roo.bootstrap.ButtonGroup
483  * @extends Roo.bootstrap.Component
484  * Bootstrap ButtonGroup class
485  * @cfg {String} size lg | sm | xs (default empty normal)
486  * @cfg {String} align vertical | justified  (default none)
487  * @cfg {String} direction up | down (default down)
488  * @cfg {Boolean} toolbar false | true
489  * @cfg {Boolean} btn true | false
490  * 
491  * 
492  * @constructor
493  * Create a new Input
494  * @param {Object} config The config object
495  */
496
497 Roo.bootstrap.ButtonGroup = function(config){
498     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
499 };
500
501 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
502     
503     size: '',
504     align: '',
505     direction: '',
506     toolbar: false,
507     btn: true,
508
509     getAutoCreate : function(){
510         var cfg = {
511             cls: 'btn-group',
512             html : null
513         };
514         
515         cfg.html = this.html || cfg.html;
516         
517         if (this.toolbar) {
518             cfg = {
519                 cls: 'btn-toolbar',
520                 html: null
521             };
522             
523             return cfg;
524         }
525         
526         if (['vertical','justified'].indexOf(this.align)!==-1) {
527             cfg.cls = 'btn-group-' + this.align;
528             
529             if (this.align == 'justified') {
530                 console.log(this.items);
531             }
532         }
533         
534         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
535             cfg.cls += ' btn-group-' + this.size;
536         }
537         
538         if (this.direction == 'up') {
539             cfg.cls += ' dropup' ;
540         }
541         
542         return cfg;
543     }
544    
545 });
546
547  /*
548  * - LGPL
549  *
550  * button
551  * 
552  */
553
554 /**
555  * @class Roo.bootstrap.Button
556  * @extends Roo.bootstrap.Component
557  * Bootstrap Button class
558  * @cfg {String} html The button content
559  * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default 
560  * @cfg {String} size ( lg | sm | xs)
561  * @cfg {String} tag ( a | input | submit)
562  * @cfg {String} href empty or href
563  * @cfg {Boolean} disabled default false;
564  * @cfg {Boolean} isClose default false;
565  * @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)
566  * @cfg {String} badge text for badge
567  * @cfg {String} theme (default|glow)  
568  * @cfg {Boolean} inverse dark themed version
569  * @cfg {Boolean} toggle is it a slidy toggle button
570  * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
571  * @cfg {String} ontext text for on slidy toggle state
572  * @cfg {String} offtext text for off slidy toggle state
573  * @cfg {Boolean} preventDefault  default true (stop click event triggering the URL if it's a link.)
574  * @cfg {Boolean} removeClass remove the standard class..
575  * @cfg {String} target  target for a href. (_self|_blank|_parent|_top| other)
576  * 
577  * @constructor
578  * Create a new button
579  * @param {Object} config The config object
580  */
581
582
583 Roo.bootstrap.Button = function(config){
584     Roo.bootstrap.Button.superclass.constructor.call(this, config);
585     this.weightClass = ["btn-default", 
586                        "btn-primary", 
587                        "btn-success", 
588                        "btn-info", 
589                        "btn-warning",
590                        "btn-danger",
591                        "btn-link"
592                       ],  
593     this.addEvents({
594         // raw events
595         /**
596          * @event click
597          * When a butotn is pressed
598          * @param {Roo.bootstrap.Button} btn
599          * @param {Roo.EventObject} e
600          */
601         "click" : true,
602          /**
603          * @event toggle
604          * After the button has been toggles
605          * @param {Roo.bootstrap.Button} btn
606          * @param {Roo.EventObject} e
607          * @param {boolean} pressed (also available as button.pressed)
608          */
609         "toggle" : true
610     });
611 };
612
613 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
614     html: false,
615     active: false,
616     weight: '',
617     size: '',
618     tag: 'button',
619     href: '',
620     disabled: false,
621     isClose: false,
622     glyphicon: '',
623     badge: '',
624     theme: 'default',
625     inverse: false,
626     
627     toggle: false,
628     ontext: 'ON',
629     offtext: 'OFF',
630     defaulton: true,
631     preventDefault: true,
632     removeClass: false,
633     name: false,
634     target: false,
635      
636     pressed : null,
637      
638     
639     getAutoCreate : function(){
640         
641         var cfg = {
642             tag : 'button',
643             cls : 'roo-button',
644             html: ''
645         };
646         
647         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
648             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
649             this.tag = 'button';
650         } else {
651             cfg.tag = this.tag;
652         }
653         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
654         
655         if (this.toggle == true) {
656             cfg={
657                 tag: 'div',
658                 cls: 'slider-frame roo-button',
659                 cn: [
660                     {
661                         tag: 'span',
662                         'data-on-text':'ON',
663                         'data-off-text':'OFF',
664                         cls: 'slider-button',
665                         html: this.offtext
666                     }
667                 ]
668             };
669             
670             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
671                 cfg.cls += ' '+this.weight;
672             }
673             
674             return cfg;
675         }
676         
677         if (this.isClose) {
678             cfg.cls += ' close';
679             
680             cfg["aria-hidden"] = true;
681             
682             cfg.html = "&times;";
683             
684             return cfg;
685         }
686         
687          
688         if (this.theme==='default') {
689             cfg.cls = 'btn roo-button';
690             
691             //if (this.parentType != 'Navbar') {
692             this.weight = this.weight.length ?  this.weight : 'default';
693             //}
694             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
695                 
696                 cfg.cls += ' btn-' + this.weight;
697             }
698         } else if (this.theme==='glow') {
699             
700             cfg.tag = 'a';
701             cfg.cls = 'btn-glow roo-button';
702             
703             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
704                 
705                 cfg.cls += ' ' + this.weight;
706             }
707         }
708    
709         
710         if (this.inverse) {
711             this.cls += ' inverse';
712         }
713         
714         
715         if (this.active || this.pressed === true) {
716             cfg.cls += ' active';
717         }
718         
719         if (this.disabled) {
720             cfg.disabled = 'disabled';
721         }
722         
723         if (this.items) {
724             Roo.log('changing to ul' );
725             cfg.tag = 'ul';
726             this.glyphicon = 'caret';
727         }
728         
729         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
730          
731         //gsRoo.log(this.parentType);
732         if (this.parentType === 'Navbar' && !this.parent().bar) {
733             Roo.log('changing to li?');
734             
735             cfg.tag = 'li';
736             
737             cfg.cls = '';
738             cfg.cn =  [{
739                 tag : 'a',
740                 cls : 'roo-button',
741                 html : this.html,
742                 href : this.href || '#'
743             }];
744             if (this.menu) {
745                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
746                 cfg.cls += ' dropdown';
747             }   
748             
749             delete cfg.html;
750             
751         }
752         
753        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
754         
755         if (this.glyphicon) {
756             cfg.html = ' ' + cfg.html;
757             
758             cfg.cn = [
759                 {
760                     tag: 'span',
761                     cls: 'glyphicon glyphicon-' + this.glyphicon
762                 }
763             ];
764         }
765         
766         if (this.badge) {
767             cfg.html += ' ';
768             
769             cfg.tag = 'a';
770             
771 //            cfg.cls='btn roo-button';
772             
773             cfg.href=this.href;
774             
775             var value = cfg.html;
776             
777             if(this.glyphicon){
778                 value = {
779                             tag: 'span',
780                             cls: 'glyphicon glyphicon-' + this.glyphicon,
781                             html: this.html
782                         };
783                 
784             }
785             
786             cfg.cn = [
787                 value,
788                 {
789                     tag: 'span',
790                     cls: 'badge',
791                     html: this.badge
792                 }
793             ];
794             
795             cfg.html='';
796         }
797         
798         if (this.menu) {
799             cfg.cls += ' dropdown';
800             cfg.html = typeof(cfg.html) != 'undefined' ?
801                     cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
802         }
803         
804         if (cfg.tag !== 'a' && this.href !== '') {
805             throw "Tag must be a to set href.";
806         } else if (this.href.length > 0) {
807             cfg.href = this.href;
808         }
809         
810         if(this.removeClass){
811             cfg.cls = '';
812         }
813         
814         if(this.target){
815             cfg.target = this.target;
816         }
817         
818         return cfg;
819     },
820     initEvents: function() {
821        // Roo.log('init events?');
822 //        Roo.log(this.el.dom);
823         // add the menu...
824         
825         if (typeof (this.menu) != 'undefined') {
826             this.menu.parentType = this.xtype;
827             this.menu.triggerEl = this.el;
828             this.addxtype(Roo.apply({}, this.menu));
829         }
830
831
832        if (this.el.hasClass('roo-button')) {
833             this.el.on('click', this.onClick, this);
834        } else {
835             this.el.select('.roo-button').on('click', this.onClick, this);
836        }
837        
838        if(this.removeClass){
839            this.el.on('click', this.onClick, this);
840        }
841        
842        this.el.enableDisplayMode();
843         
844     },
845     onClick : function(e)
846     {
847         if (this.disabled) {
848             return;
849         }
850         
851         Roo.log('button on click ');
852         if(this.preventDefault){
853             e.preventDefault();
854         }
855         
856         if (this.pressed === true || this.pressed === false) {
857             this.toggleActive(e);
858         }
859         
860         
861         this.fireEvent('click', this, e);
862     },
863     
864     /**
865      * Enables this button
866      */
867     enable : function()
868     {
869         this.disabled = false;
870         this.el.removeClass('disabled');
871     },
872     
873     /**
874      * Disable this button
875      */
876     disable : function()
877     {
878         this.disabled = true;
879         this.el.addClass('disabled');
880     },
881      /**
882      * sets the active state on/off, 
883      * @param {Boolean} state (optional) Force a particular state
884      */
885     setActive : function(v) {
886         
887         this.el[v ? 'addClass' : 'removeClass']('active');
888         this.pressed = v;
889     },
890      /**
891      * toggles the current active state 
892      */
893     toggleActive : function(e)
894     {
895         this.setActive(!this.pressed);
896         this.fireEvent('toggle', this, e, !this.pressed);
897     },
898      /**
899      * get the current active state
900      * @return {boolean} true if it's active
901      */
902     isActive : function()
903     {
904         return this.el.hasClass('active');
905     },
906     /**
907      * set the text of the first selected button
908      */
909     setText : function(str)
910     {
911         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
912     },
913     /**
914      * get the text of the first selected button
915      */
916     getText : function()
917     {
918         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
919     },
920     hide: function() {
921        
922      
923         this.el.hide();   
924     },
925     show: function() {
926        
927         this.el.show();   
928     },
929     setWeight : function(str)
930     {
931         this.el.removeClass(this.weightClass);
932         this.el.addClass('btn-' + str);        
933     }
934     
935     
936 });
937
938  /*
939  * - LGPL
940  *
941  * column
942  * 
943  */
944
945 /**
946  * @class Roo.bootstrap.Column
947  * @extends Roo.bootstrap.Component
948  * Bootstrap Column class
949  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
950  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
951  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
952  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
953  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
954  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
955  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
956  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
957  *
958  * 
959  * @cfg {Boolean} hidden (true|false) hide the element
960  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
961  * @cfg {String} fa (ban|check|...) font awesome icon
962  * @cfg {Number} fasize (1|2|....) font awsome size
963
964  * @cfg {String} icon (info-sign|check|...) glyphicon name
965
966  * @cfg {String} html content of column.
967  * 
968  * @constructor
969  * Create a new Column
970  * @param {Object} config The config object
971  */
972
973 Roo.bootstrap.Column = function(config){
974     Roo.bootstrap.Column.superclass.constructor.call(this, config);
975 };
976
977 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
978     
979     xs: false,
980     sm: false,
981     md: false,
982     lg: false,
983     xsoff: false,
984     smoff: false,
985     mdoff: false,
986     lgoff: false,
987     html: '',
988     offset: 0,
989     alert: false,
990     fa: false,
991     icon : false,
992     hidden : false,
993     fasize : 1,
994     
995     getAutoCreate : function(){
996         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
997         
998         cfg = {
999             tag: 'div',
1000             cls: 'column'
1001         };
1002         
1003         var settings=this;
1004         ['xs','sm','md','lg'].map(function(size){
1005             //Roo.log( size + ':' + settings[size]);
1006             
1007             if (settings[size+'off'] !== false) {
1008                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1009             }
1010             
1011             if (settings[size] === false) {
1012                 return;
1013             }
1014             
1015             if (!settings[size]) { // 0 = hidden
1016                 cfg.cls += ' hidden-' + size;
1017                 return;
1018             }
1019             cfg.cls += ' col-' + size + '-' + settings[size];
1020             
1021         });
1022         
1023         if (this.hidden) {
1024             cfg.cls += ' hidden';
1025         }
1026         
1027         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1028             cfg.cls +=' alert alert-' + this.alert;
1029         }
1030         
1031         
1032         if (this.html.length) {
1033             cfg.html = this.html;
1034         }
1035         if (this.fa) {
1036             var fasize = '';
1037             if (this.fasize > 1) {
1038                 fasize = ' fa-' + this.fasize + 'x';
1039             }
1040             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1041             
1042             
1043         }
1044         if (this.icon) {
1045             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' +  (cfg.html || '');
1046         }
1047         
1048         return cfg;
1049     }
1050    
1051 });
1052
1053  
1054
1055  /*
1056  * - LGPL
1057  *
1058  * page container.
1059  * 
1060  */
1061
1062
1063 /**
1064  * @class Roo.bootstrap.Container
1065  * @extends Roo.bootstrap.Component
1066  * Bootstrap Container class
1067  * @cfg {Boolean} jumbotron is it a jumbotron element
1068  * @cfg {String} html content of element
1069  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1070  * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel  - type - primary/success.....
1071  * @cfg {String} header content of header (for panel)
1072  * @cfg {String} footer content of footer (for panel)
1073  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1074  * @cfg {String} tag (header|aside|section) type of HTML tag.
1075  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1076  * @cfg {String} fa font awesome icon
1077  * @cfg {String} icon (info-sign|check|...) glyphicon name
1078  * @cfg {Boolean} hidden (true|false) hide the element
1079  * @cfg {Boolean} expandable (true|false) default false
1080  * @cfg {Boolean} expanded (true|false) default true
1081  * @cfg {String} rheader contet on the right of header
1082  * @cfg {Boolean} clickable (true|false) default false
1083
1084  *     
1085  * @constructor
1086  * Create a new Container
1087  * @param {Object} config The config object
1088  */
1089
1090 Roo.bootstrap.Container = function(config){
1091     Roo.bootstrap.Container.superclass.constructor.call(this, config);
1092     
1093     this.addEvents({
1094         // raw events
1095          /**
1096          * @event expand
1097          * After the panel has been expand
1098          * 
1099          * @param {Roo.bootstrap.Container} this
1100          */
1101         "expand" : true,
1102         /**
1103          * @event collapse
1104          * After the panel has been collapsed
1105          * 
1106          * @param {Roo.bootstrap.Container} this
1107          */
1108         "collapse" : true,
1109         /**
1110          * @event click
1111          * When a element is chick
1112          * @param {Roo.bootstrap.Container} this
1113          * @param {Roo.EventObject} e
1114          */
1115         "click" : true
1116     });
1117 };
1118
1119 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
1120     
1121     jumbotron : false,
1122     well: '',
1123     panel : '',
1124     header: '',
1125     footer : '',
1126     sticky: '',
1127     tag : false,
1128     alert : false,
1129     fa: false,
1130     icon : false,
1131     expandable : false,
1132     rheader : '',
1133     expanded : true,
1134     clickable: false,
1135   
1136      
1137     getChildContainer : function() {
1138         
1139         if(!this.el){
1140             return false;
1141         }
1142         
1143         if (this.panel.length) {
1144             return this.el.select('.panel-body',true).first();
1145         }
1146         
1147         return this.el;
1148     },
1149     
1150     
1151     getAutoCreate : function(){
1152         
1153         var cfg = {
1154             tag : this.tag || 'div',
1155             html : '',
1156             cls : ''
1157         };
1158         if (this.jumbotron) {
1159             cfg.cls = 'jumbotron';
1160         }
1161         
1162         
1163         
1164         // - this is applied by the parent..
1165         //if (this.cls) {
1166         //    cfg.cls = this.cls + '';
1167         //}
1168         
1169         if (this.sticky.length) {
1170             
1171             var bd = Roo.get(document.body);
1172             if (!bd.hasClass('bootstrap-sticky')) {
1173                 bd.addClass('bootstrap-sticky');
1174                 Roo.select('html',true).setStyle('height', '100%');
1175             }
1176              
1177             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1178         }
1179         
1180         
1181         if (this.well.length) {
1182             switch (this.well) {
1183                 case 'lg':
1184                 case 'sm':
1185                     cfg.cls +=' well well-' +this.well;
1186                     break;
1187                 default:
1188                     cfg.cls +=' well';
1189                     break;
1190             }
1191         }
1192         
1193         if (this.hidden) {
1194             cfg.cls += ' hidden';
1195         }
1196         
1197         
1198         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1199             cfg.cls +=' alert alert-' + this.alert;
1200         }
1201         
1202         var body = cfg;
1203         
1204         if (this.panel.length) {
1205             cfg.cls += ' panel panel-' + this.panel;
1206             cfg.cn = [];
1207             if (this.header.length) {
1208                 
1209                 var h = [];
1210                 
1211                 if(this.expandable){
1212                     
1213                     cfg.cls = cfg.cls + ' expandable';
1214                     
1215                     h.push({
1216                         tag: 'i',
1217                         cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus') 
1218                     });
1219                     
1220                 }
1221                 
1222                 h.push(
1223                     {
1224                         tag: 'span',
1225                         cls : 'panel-title',
1226                         html : (this.expandable ? '&nbsp;' : '') + this.header
1227                     },
1228                     {
1229                         tag: 'span',
1230                         cls: 'panel-header-right',
1231                         html: this.rheader
1232                     }
1233                 );
1234                 
1235                 cfg.cn.push({
1236                     cls : 'panel-heading',
1237                     style : this.expandable ? 'cursor: pointer' : '',
1238                     cn : h
1239                 });
1240                 
1241             }
1242             
1243             body = false;
1244             cfg.cn.push({
1245                 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1246                 html : this.html
1247             });
1248             
1249             
1250             if (this.footer.length) {
1251                 cfg.cn.push({
1252                     cls : 'panel-footer',
1253                     html : this.footer
1254                     
1255                 });
1256             }
1257             
1258         }
1259         
1260         if (body) {
1261             body.html = this.html || cfg.html;
1262             // prefix with the icons..
1263             if (this.fa) {
1264                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1265             }
1266             if (this.icon) {
1267                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1268             }
1269             
1270             
1271         }
1272         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1273             cfg.cls =  'container';
1274         }
1275         
1276         return cfg;
1277     },
1278     
1279     initEvents: function() 
1280     {
1281         if(this.expandable){
1282             var headerEl = this.headerEl();
1283         
1284             if(headerEl){
1285                 headerEl.on('click', this.onToggleClick, this);
1286             }
1287         }
1288         
1289         if(this.clickable){
1290             this.el.on('click', this.onClick, this);
1291         }
1292         
1293     },
1294     
1295     onToggleClick : function()
1296     {
1297         var headerEl = this.headerEl();
1298         
1299         if(!headerEl){
1300             return;
1301         }
1302         
1303         if(this.expanded){
1304             this.collapse();
1305             return;
1306         }
1307         
1308         this.expand();
1309     },
1310     
1311     expand : function()
1312     {
1313         if(this.fireEvent('expand', this)) {
1314             
1315             this.expanded = true;
1316             
1317             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1318             
1319             this.el.select('.panel-body',true).first().removeClass('hide');
1320             
1321             var toggleEl = this.toggleEl();
1322
1323             if(!toggleEl){
1324                 return;
1325             }
1326
1327             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1328         }
1329         
1330     },
1331     
1332     collapse : function()
1333     {
1334         if(this.fireEvent('collapse', this)) {
1335             
1336             this.expanded = false;
1337             
1338             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1339             this.el.select('.panel-body',true).first().addClass('hide');
1340         
1341             var toggleEl = this.toggleEl();
1342
1343             if(!toggleEl){
1344                 return;
1345             }
1346
1347             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1348         }
1349     },
1350     
1351     toggleEl : function()
1352     {
1353         if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1354             return;
1355         }
1356         
1357         return this.el.select('.panel-heading .fa',true).first();
1358     },
1359     
1360     headerEl : function()
1361     {
1362         if(!this.el || !this.panel.length || !this.header.length){
1363             return;
1364         }
1365         
1366         return this.el.select('.panel-heading',true).first()
1367     },
1368     
1369     bodyEl : function()
1370     {
1371         if(!this.el || !this.panel.length){
1372             return;
1373         }
1374         
1375         return this.el.select('.panel-body',true).first()
1376     },
1377     
1378     titleEl : function()
1379     {
1380         if(!this.el || !this.panel.length || !this.header.length){
1381             return;
1382         }
1383         
1384         return this.el.select('.panel-title',true).first();
1385     },
1386     
1387     setTitle : function(v)
1388     {
1389         var titleEl = this.titleEl();
1390         
1391         if(!titleEl){
1392             return;
1393         }
1394         
1395         titleEl.dom.innerHTML = v;
1396     },
1397     
1398     getTitle : function()
1399     {
1400         
1401         var titleEl = this.titleEl();
1402         
1403         if(!titleEl){
1404             return '';
1405         }
1406         
1407         return titleEl.dom.innerHTML;
1408     },
1409     
1410     setRightTitle : function(v)
1411     {
1412         var t = this.el.select('.panel-header-right',true).first();
1413         
1414         if(!t){
1415             return;
1416         }
1417         
1418         t.dom.innerHTML = v;
1419     },
1420     
1421     onClick : function(e)
1422     {
1423         e.preventDefault();
1424         
1425         this.fireEvent('click', this, e);
1426     }
1427 });
1428
1429  /*
1430  * - LGPL
1431  *
1432  * image
1433  * 
1434  */
1435
1436
1437 /**
1438  * @class Roo.bootstrap.Img
1439  * @extends Roo.bootstrap.Component
1440  * Bootstrap Img class
1441  * @cfg {Boolean} imgResponsive false | true
1442  * @cfg {String} border rounded | circle | thumbnail
1443  * @cfg {String} src image source
1444  * @cfg {String} alt image alternative text
1445  * @cfg {String} href a tag href
1446  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1447  * @cfg {String} xsUrl xs image source
1448  * @cfg {String} smUrl sm image source
1449  * @cfg {String} mdUrl md image source
1450  * @cfg {String} lgUrl lg image source
1451  * 
1452  * @constructor
1453  * Create a new Input
1454  * @param {Object} config The config object
1455  */
1456
1457 Roo.bootstrap.Img = function(config){
1458     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1459     
1460     this.addEvents({
1461         // img events
1462         /**
1463          * @event click
1464          * The img click event for the img.
1465          * @param {Roo.EventObject} e
1466          */
1467         "click" : true
1468     });
1469 };
1470
1471 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1472     
1473     imgResponsive: true,
1474     border: '',
1475     src: 'about:blank',
1476     href: false,
1477     target: false,
1478     xsUrl: '',
1479     smUrl: '',
1480     mdUrl: '',
1481     lgUrl: '',
1482
1483     getAutoCreate : function()
1484     {   
1485         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1486             return this.createSingleImg();
1487         }
1488         
1489         var cfg = {
1490             tag: 'div',
1491             cls: 'roo-image-responsive-group',
1492             cn: []
1493         };
1494         var _this = this;
1495         
1496         Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1497             
1498             if(!_this[size + 'Url']){
1499                 return;
1500             }
1501             
1502             var img = {
1503                 tag: 'img',
1504                 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1505                 html: _this.html || cfg.html,
1506                 src: _this[size + 'Url']
1507             };
1508             
1509             img.cls += ' roo-image-responsive-' + size;
1510             
1511             var s = ['xs', 'sm', 'md', 'lg'];
1512             
1513             s.splice(s.indexOf(size), 1);
1514             
1515             Roo.each(s, function(ss){
1516                 img.cls += ' hidden-' + ss;
1517             });
1518             
1519             if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1520                 cfg.cls += ' img-' + _this.border;
1521             }
1522             
1523             if(_this.alt){
1524                 cfg.alt = _this.alt;
1525             }
1526             
1527             if(_this.href){
1528                 var a = {
1529                     tag: 'a',
1530                     href: _this.href,
1531                     cn: [
1532                         img
1533                     ]
1534                 };
1535
1536                 if(this.target){
1537                     a.target = _this.target;
1538                 }
1539             }
1540             
1541             cfg.cn.push((_this.href) ? a : img);
1542             
1543         });
1544         
1545         return cfg;
1546     },
1547     
1548     createSingleImg : function()
1549     {
1550         var cfg = {
1551             tag: 'img',
1552             cls: (this.imgResponsive) ? 'img-responsive' : '',
1553             html : null,
1554             src : 'about:blank'  // just incase src get's set to undefined?!?
1555         };
1556         
1557         cfg.html = this.html || cfg.html;
1558         
1559         cfg.src = this.src || cfg.src;
1560         
1561         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1562             cfg.cls += ' img-' + this.border;
1563         }
1564         
1565         if(this.alt){
1566             cfg.alt = this.alt;
1567         }
1568         
1569         if(this.href){
1570             var a = {
1571                 tag: 'a',
1572                 href: this.href,
1573                 cn: [
1574                     cfg
1575                 ]
1576             };
1577             
1578             if(this.target){
1579                 a.target = this.target;
1580             }
1581             
1582         }
1583         
1584         return (this.href) ? a : cfg;
1585     },
1586     
1587     initEvents: function() 
1588     {
1589         if(!this.href){
1590             this.el.on('click', this.onClick, this);
1591         }
1592         
1593     },
1594     
1595     onClick : function(e)
1596     {
1597         Roo.log('img onclick');
1598         this.fireEvent('click', this, e);
1599     },
1600     /**
1601      * Sets the url of the image - used to update it
1602      * @param {String} url the url of the image
1603      */
1604     
1605     setSrc : function(url)
1606     {
1607         this.src =  url;
1608         
1609         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1610             this.el.dom.src =  url;
1611             return;
1612         }
1613         
1614         this.el.select('img', true).first().dom.src =  url;
1615     }
1616     
1617     
1618    
1619 });
1620
1621  /*
1622  * - LGPL
1623  *
1624  * image
1625  * 
1626  */
1627
1628
1629 /**
1630  * @class Roo.bootstrap.Link
1631  * @extends Roo.bootstrap.Component
1632  * Bootstrap Link Class
1633  * @cfg {String} alt image alternative text
1634  * @cfg {String} href a tag href
1635  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1636  * @cfg {String} html the content of the link.
1637  * @cfg {String} anchor name for the anchor link
1638  * @cfg {String} fa - favicon
1639
1640  * @cfg {Boolean} preventDefault (true | false) default false
1641
1642  * 
1643  * @constructor
1644  * Create a new Input
1645  * @param {Object} config The config object
1646  */
1647
1648 Roo.bootstrap.Link = function(config){
1649     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1650     
1651     this.addEvents({
1652         // img events
1653         /**
1654          * @event click
1655          * The img click event for the img.
1656          * @param {Roo.EventObject} e
1657          */
1658         "click" : true
1659     });
1660 };
1661
1662 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1663     
1664     href: false,
1665     target: false,
1666     preventDefault: false,
1667     anchor : false,
1668     alt : false,
1669     fa: false,
1670
1671
1672     getAutoCreate : function()
1673     {
1674         var html = this.html || '';
1675         
1676         if (this.fa !== false) {
1677             html = '<i class="fa fa-' + this.fa + '"></i>';
1678         }
1679         var cfg = {
1680             tag: 'a'
1681         };
1682         // anchor's do not require html/href...
1683         if (this.anchor === false) {
1684             cfg.html = html;
1685             cfg.href = this.href || '#';
1686         } else {
1687             cfg.name = this.anchor;
1688             if (this.html !== false || this.fa !== false) {
1689                 cfg.html = html;
1690             }
1691             if (this.href !== false) {
1692                 cfg.href = this.href;
1693             }
1694         }
1695         
1696         if(this.alt !== false){
1697             cfg.alt = this.alt;
1698         }
1699         
1700         
1701         if(this.target !== false) {
1702             cfg.target = this.target;
1703         }
1704         
1705         return cfg;
1706     },
1707     
1708     initEvents: function() {
1709         
1710         if(!this.href || this.preventDefault){
1711             this.el.on('click', this.onClick, this);
1712         }
1713     },
1714     
1715     onClick : function(e)
1716     {
1717         if(this.preventDefault){
1718             e.preventDefault();
1719         }
1720         //Roo.log('img onclick');
1721         this.fireEvent('click', this, e);
1722     }
1723    
1724 });
1725
1726  /*
1727  * - LGPL
1728  *
1729  * header
1730  * 
1731  */
1732
1733 /**
1734  * @class Roo.bootstrap.Header
1735  * @extends Roo.bootstrap.Component
1736  * Bootstrap Header class
1737  * @cfg {String} html content of header
1738  * @cfg {Number} level (1|2|3|4|5|6) default 1
1739  * 
1740  * @constructor
1741  * Create a new Header
1742  * @param {Object} config The config object
1743  */
1744
1745
1746 Roo.bootstrap.Header  = function(config){
1747     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1748 };
1749
1750 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1751     
1752     //href : false,
1753     html : false,
1754     level : 1,
1755     
1756     
1757     
1758     getAutoCreate : function(){
1759         
1760         
1761         
1762         var cfg = {
1763             tag: 'h' + (1 *this.level),
1764             html: this.html || ''
1765         } ;
1766         
1767         return cfg;
1768     }
1769    
1770 });
1771
1772  
1773
1774  /*
1775  * Based on:
1776  * Ext JS Library 1.1.1
1777  * Copyright(c) 2006-2007, Ext JS, LLC.
1778  *
1779  * Originally Released Under LGPL - original licence link has changed is not relivant.
1780  *
1781  * Fork - LGPL
1782  * <script type="text/javascript">
1783  */
1784  
1785 /**
1786  * @class Roo.bootstrap.MenuMgr
1787  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1788  * @singleton
1789  */
1790 Roo.bootstrap.MenuMgr = function(){
1791    var menus, active, groups = {}, attached = false, lastShow = new Date();
1792
1793    // private - called when first menu is created
1794    function init(){
1795        menus = {};
1796        active = new Roo.util.MixedCollection();
1797        Roo.get(document).addKeyListener(27, function(){
1798            if(active.length > 0){
1799                hideAll();
1800            }
1801        });
1802    }
1803
1804    // private
1805    function hideAll(){
1806        if(active && active.length > 0){
1807            var c = active.clone();
1808            c.each(function(m){
1809                m.hide();
1810            });
1811        }
1812    }
1813
1814    // private
1815    function onHide(m){
1816        active.remove(m);
1817        if(active.length < 1){
1818            Roo.get(document).un("mouseup", onMouseDown);
1819             
1820            attached = false;
1821        }
1822    }
1823
1824    // private
1825    function onShow(m){
1826        var last = active.last();
1827        lastShow = new Date();
1828        active.add(m);
1829        if(!attached){
1830           Roo.get(document).on("mouseup", onMouseDown);
1831            
1832            attached = true;
1833        }
1834        if(m.parentMenu){
1835           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1836           m.parentMenu.activeChild = m;
1837        }else if(last && last.isVisible()){
1838           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1839        }
1840    }
1841
1842    // private
1843    function onBeforeHide(m){
1844        if(m.activeChild){
1845            m.activeChild.hide();
1846        }
1847        if(m.autoHideTimer){
1848            clearTimeout(m.autoHideTimer);
1849            delete m.autoHideTimer;
1850        }
1851    }
1852
1853    // private
1854    function onBeforeShow(m){
1855        var pm = m.parentMenu;
1856        if(!pm && !m.allowOtherMenus){
1857            hideAll();
1858        }else if(pm && pm.activeChild && active != m){
1859            pm.activeChild.hide();
1860        }
1861    }
1862
1863    // private this should really trigger on mouseup..
1864    function onMouseDown(e){
1865         Roo.log("on Mouse Up");
1866         
1867         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1868             Roo.log("MenuManager hideAll");
1869             hideAll();
1870             e.stopEvent();
1871         }
1872         
1873         
1874    }
1875
1876    // private
1877    function onBeforeCheck(mi, state){
1878        if(state){
1879            var g = groups[mi.group];
1880            for(var i = 0, l = g.length; i < l; i++){
1881                if(g[i] != mi){
1882                    g[i].setChecked(false);
1883                }
1884            }
1885        }
1886    }
1887
1888    return {
1889
1890        /**
1891         * Hides all menus that are currently visible
1892         */
1893        hideAll : function(){
1894             hideAll();  
1895        },
1896
1897        // private
1898        register : function(menu){
1899            if(!menus){
1900                init();
1901            }
1902            menus[menu.id] = menu;
1903            menu.on("beforehide", onBeforeHide);
1904            menu.on("hide", onHide);
1905            menu.on("beforeshow", onBeforeShow);
1906            menu.on("show", onShow);
1907            var g = menu.group;
1908            if(g && menu.events["checkchange"]){
1909                if(!groups[g]){
1910                    groups[g] = [];
1911                }
1912                groups[g].push(menu);
1913                menu.on("checkchange", onCheck);
1914            }
1915        },
1916
1917         /**
1918          * Returns a {@link Roo.menu.Menu} object
1919          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1920          * be used to generate and return a new Menu instance.
1921          */
1922        get : function(menu){
1923            if(typeof menu == "string"){ // menu id
1924                return menus[menu];
1925            }else if(menu.events){  // menu instance
1926                return menu;
1927            }
1928            /*else if(typeof menu.length == 'number'){ // array of menu items?
1929                return new Roo.bootstrap.Menu({items:menu});
1930            }else{ // otherwise, must be a config
1931                return new Roo.bootstrap.Menu(menu);
1932            }
1933            */
1934            return false;
1935        },
1936
1937        // private
1938        unregister : function(menu){
1939            delete menus[menu.id];
1940            menu.un("beforehide", onBeforeHide);
1941            menu.un("hide", onHide);
1942            menu.un("beforeshow", onBeforeShow);
1943            menu.un("show", onShow);
1944            var g = menu.group;
1945            if(g && menu.events["checkchange"]){
1946                groups[g].remove(menu);
1947                menu.un("checkchange", onCheck);
1948            }
1949        },
1950
1951        // private
1952        registerCheckable : function(menuItem){
1953            var g = menuItem.group;
1954            if(g){
1955                if(!groups[g]){
1956                    groups[g] = [];
1957                }
1958                groups[g].push(menuItem);
1959                menuItem.on("beforecheckchange", onBeforeCheck);
1960            }
1961        },
1962
1963        // private
1964        unregisterCheckable : function(menuItem){
1965            var g = menuItem.group;
1966            if(g){
1967                groups[g].remove(menuItem);
1968                menuItem.un("beforecheckchange", onBeforeCheck);
1969            }
1970        }
1971    };
1972 }();/*
1973  * - LGPL
1974  *
1975  * menu
1976  * 
1977  */
1978
1979 /**
1980  * @class Roo.bootstrap.Menu
1981  * @extends Roo.bootstrap.Component
1982  * Bootstrap Menu class - container for MenuItems
1983  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1984  * @cfg {bool} hidden  if the menu should be hidden when rendered.
1985  * @cfg {bool} stopEvent (true|false)  Stop event after trigger press (default true)
1986  * @cfg {bool} isLink (true|false)  the menu has link disable auto expand and collaspe (default false)
1987  * 
1988  * @constructor
1989  * Create a new Menu
1990  * @param {Object} config The config object
1991  */
1992
1993
1994 Roo.bootstrap.Menu = function(config){
1995     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1996     if (this.registerMenu && this.type != 'treeview')  {
1997         Roo.bootstrap.MenuMgr.register(this);
1998     }
1999     this.addEvents({
2000         /**
2001          * @event beforeshow
2002          * Fires before this menu is displayed
2003          * @param {Roo.menu.Menu} this
2004          */
2005         beforeshow : true,
2006         /**
2007          * @event beforehide
2008          * Fires before this menu is hidden
2009          * @param {Roo.menu.Menu} this
2010          */
2011         beforehide : true,
2012         /**
2013          * @event show
2014          * Fires after this menu is displayed
2015          * @param {Roo.menu.Menu} this
2016          */
2017         show : true,
2018         /**
2019          * @event hide
2020          * Fires after this menu is hidden
2021          * @param {Roo.menu.Menu} this
2022          */
2023         hide : true,
2024         /**
2025          * @event click
2026          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2027          * @param {Roo.menu.Menu} this
2028          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2029          * @param {Roo.EventObject} e
2030          */
2031         click : true,
2032         /**
2033          * @event mouseover
2034          * Fires when the mouse is hovering over this menu
2035          * @param {Roo.menu.Menu} this
2036          * @param {Roo.EventObject} e
2037          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2038          */
2039         mouseover : true,
2040         /**
2041          * @event mouseout
2042          * Fires when the mouse exits this menu
2043          * @param {Roo.menu.Menu} this
2044          * @param {Roo.EventObject} e
2045          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2046          */
2047         mouseout : true,
2048         /**
2049          * @event itemclick
2050          * Fires when a menu item contained in this menu is clicked
2051          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2052          * @param {Roo.EventObject} e
2053          */
2054         itemclick: true
2055     });
2056     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2057 };
2058
2059 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
2060     
2061    /// html : false,
2062     //align : '',
2063     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
2064     type: false,
2065     /**
2066      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2067      */
2068     registerMenu : true,
2069     
2070     menuItems :false, // stores the menu items..
2071     
2072     hidden:true,
2073         
2074     parentMenu : false,
2075     
2076     stopEvent : true,
2077     
2078     isLink : false,
2079     
2080     getChildContainer : function() {
2081         return this.el;  
2082     },
2083     
2084     getAutoCreate : function(){
2085          
2086         //if (['right'].indexOf(this.align)!==-1) {
2087         //    cfg.cn[1].cls += ' pull-right'
2088         //}
2089         
2090         
2091         var cfg = {
2092             tag : 'ul',
2093             cls : 'dropdown-menu' ,
2094             style : 'z-index:1000'
2095             
2096         };
2097         
2098         if (this.type === 'submenu') {
2099             cfg.cls = 'submenu active';
2100         }
2101         if (this.type === 'treeview') {
2102             cfg.cls = 'treeview-menu';
2103         }
2104         
2105         return cfg;
2106     },
2107     initEvents : function() {
2108         
2109        // Roo.log("ADD event");
2110        // Roo.log(this.triggerEl.dom);
2111         
2112         this.triggerEl.on('click', this.onTriggerClick, this);
2113         
2114         this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2115         
2116         this.triggerEl.addClass('dropdown-toggle');
2117         
2118         if (Roo.isTouch) {
2119             this.el.on('touchstart'  , this.onTouch, this);
2120         }
2121         this.el.on('click' , this.onClick, this);
2122
2123         this.el.on("mouseover", this.onMouseOver, this);
2124         this.el.on("mouseout", this.onMouseOut, this);
2125         
2126     },
2127     
2128     findTargetItem : function(e)
2129     {
2130         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
2131         if(!t){
2132             return false;
2133         }
2134         //Roo.log(t);         Roo.log(t.id);
2135         if(t && t.id){
2136             //Roo.log(this.menuitems);
2137             return this.menuitems.get(t.id);
2138             
2139             //return this.items.get(t.menuItemId);
2140         }
2141         
2142         return false;
2143     },
2144     
2145     onTouch : function(e) 
2146     {
2147         Roo.log("menu.onTouch");
2148         //e.stopEvent(); this make the user popdown broken
2149         this.onClick(e);
2150     },
2151     
2152     onClick : function(e)
2153     {
2154         Roo.log("menu.onClick");
2155         
2156         var t = this.findTargetItem(e);
2157         if(!t || t.isContainer){
2158             return;
2159         }
2160         Roo.log(e);
2161         /*
2162         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
2163             if(t == this.activeItem && t.shouldDeactivate(e)){
2164                 this.activeItem.deactivate();
2165                 delete this.activeItem;
2166                 return;
2167             }
2168             if(t.canActivate){
2169                 this.setActiveItem(t, true);
2170             }
2171             return;
2172             
2173             
2174         }
2175         */
2176        
2177         Roo.log('pass click event');
2178         
2179         t.onClick(e);
2180         
2181         this.fireEvent("click", this, t, e);
2182         
2183         var _this = this;
2184         
2185         if(!t.href.length || t.href == '#'){
2186             (function() { _this.hide(); }).defer(100);
2187         }
2188         
2189     },
2190     
2191     onMouseOver : function(e){
2192         var t  = this.findTargetItem(e);
2193         //Roo.log(t);
2194         //if(t){
2195         //    if(t.canActivate && !t.disabled){
2196         //        this.setActiveItem(t, true);
2197         //    }
2198         //}
2199         
2200         this.fireEvent("mouseover", this, e, t);
2201     },
2202     isVisible : function(){
2203         return !this.hidden;
2204     },
2205      onMouseOut : function(e){
2206         var t  = this.findTargetItem(e);
2207         
2208         //if(t ){
2209         //    if(t == this.activeItem && t.shouldDeactivate(e)){
2210         //        this.activeItem.deactivate();
2211         //        delete this.activeItem;
2212         //    }
2213         //}
2214         this.fireEvent("mouseout", this, e, t);
2215     },
2216     
2217     
2218     /**
2219      * Displays this menu relative to another element
2220      * @param {String/HTMLElement/Roo.Element} element The element to align to
2221      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2222      * the element (defaults to this.defaultAlign)
2223      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2224      */
2225     show : function(el, pos, parentMenu){
2226         this.parentMenu = parentMenu;
2227         if(!this.el){
2228             this.render();
2229         }
2230         this.fireEvent("beforeshow", this);
2231         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2232     },
2233      /**
2234      * Displays this menu at a specific xy position
2235      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2236      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2237      */
2238     showAt : function(xy, parentMenu, /* private: */_e){
2239         this.parentMenu = parentMenu;
2240         if(!this.el){
2241             this.render();
2242         }
2243         if(_e !== false){
2244             this.fireEvent("beforeshow", this);
2245             //xy = this.el.adjustForConstraints(xy);
2246         }
2247         
2248         //this.el.show();
2249         this.hideMenuItems();
2250         this.hidden = false;
2251         this.triggerEl.addClass('open');
2252         
2253         // reassign x when hitting right
2254         if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2255             xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2256         }
2257         
2258         // reassign y when hitting bottom
2259         if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2260             xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2261         }
2262         
2263         // but the list may align on trigger left or trigger top... should it be a properity?
2264         
2265         if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2266             this.el.setXY(xy);
2267         }
2268         
2269         this.focus();
2270         this.fireEvent("show", this);
2271     },
2272     
2273     focus : function(){
2274         return;
2275         if(!this.hidden){
2276             this.doFocus.defer(50, this);
2277         }
2278     },
2279
2280     doFocus : function(){
2281         if(!this.hidden){
2282             this.focusEl.focus();
2283         }
2284     },
2285
2286     /**
2287      * Hides this menu and optionally all parent menus
2288      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2289      */
2290     hide : function(deep)
2291     {
2292         
2293         this.hideMenuItems();
2294         if(this.el && this.isVisible()){
2295             this.fireEvent("beforehide", this);
2296             if(this.activeItem){
2297                 this.activeItem.deactivate();
2298                 this.activeItem = null;
2299             }
2300             this.triggerEl.removeClass('open');;
2301             this.hidden = true;
2302             this.fireEvent("hide", this);
2303         }
2304         if(deep === true && this.parentMenu){
2305             this.parentMenu.hide(true);
2306         }
2307     },
2308     
2309     onTriggerClick : function(e)
2310     {
2311         Roo.log('trigger click');
2312         
2313         var target = e.getTarget();
2314         
2315         Roo.log(target.nodeName.toLowerCase());
2316         
2317         if(target.nodeName.toLowerCase() === 'i'){
2318             e.preventDefault();
2319         }
2320         
2321     },
2322     
2323     onTriggerPress  : function(e)
2324     {
2325         Roo.log('trigger press');
2326         //Roo.log(e.getTarget());
2327        // Roo.log(this.triggerEl.dom);
2328        
2329         // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2330         var pel = Roo.get(e.getTarget());
2331         if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2332             Roo.log('is treeview or dropdown?');
2333             return;
2334         }
2335         
2336         if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2337             return;
2338         }
2339         
2340         if (this.isVisible()) {
2341             Roo.log('hide');
2342             this.hide();
2343         } else {
2344             Roo.log('show');
2345             this.show(this.triggerEl, false, false);
2346         }
2347         
2348         if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2349             e.stopEvent();
2350         }
2351         
2352     },
2353        
2354     
2355     hideMenuItems : function()
2356     {
2357         Roo.log("hide Menu Items");
2358         if (!this.el) { 
2359             return;
2360         }
2361         //$(backdrop).remove()
2362         this.el.select('.open',true).each(function(aa) {
2363             
2364             aa.removeClass('open');
2365           //var parent = getParent($(this))
2366           //var relatedTarget = { relatedTarget: this }
2367           
2368            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2369           //if (e.isDefaultPrevented()) return
2370            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2371         });
2372     },
2373     addxtypeChild : function (tree, cntr) {
2374         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2375           
2376         this.menuitems.add(comp);
2377         return comp;
2378
2379     },
2380     getEl : function()
2381     {
2382         Roo.log(this.el);
2383         return this.el;
2384     },
2385     
2386     clear : function()
2387     {
2388         this.getEl().dom.innerHTML = '';
2389         this.menuitems.clear();
2390     }
2391 });
2392
2393  
2394  /*
2395  * - LGPL
2396  *
2397  * menu item
2398  * 
2399  */
2400
2401
2402 /**
2403  * @class Roo.bootstrap.MenuItem
2404  * @extends Roo.bootstrap.Component
2405  * Bootstrap MenuItem class
2406  * @cfg {String} html the menu label
2407  * @cfg {String} href the link
2408  * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2409  * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2410  * @cfg {Boolean} active  used on sidebars to highlight active itesm
2411  * @cfg {String} fa favicon to show on left of menu item.
2412  * @cfg {Roo.bootsrap.Menu} menu the child menu.
2413  * 
2414  * 
2415  * @constructor
2416  * Create a new MenuItem
2417  * @param {Object} config The config object
2418  */
2419
2420
2421 Roo.bootstrap.MenuItem = function(config){
2422     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2423     this.addEvents({
2424         // raw events
2425         /**
2426          * @event click
2427          * The raw click event for the entire grid.
2428          * @param {Roo.bootstrap.MenuItem} this
2429          * @param {Roo.EventObject} e
2430          */
2431         "click" : true
2432     });
2433 };
2434
2435 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
2436     
2437     href : false,
2438     html : false,
2439     preventDefault: false,
2440     isContainer : false,
2441     active : false,
2442     fa: false,
2443     
2444     getAutoCreate : function(){
2445         
2446         if(this.isContainer){
2447             return {
2448                 tag: 'li',
2449                 cls: 'dropdown-menu-item'
2450             };
2451         }
2452         var ctag = {
2453             tag: 'span',
2454             html: 'Link'
2455         };
2456         
2457         var anc = {
2458             tag : 'a',
2459             href : '#',
2460             cn : [  ]
2461         };
2462         
2463         if (this.fa !== false) {
2464             anc.cn.push({
2465                 tag : 'i',
2466                 cls : 'fa fa-' + this.fa
2467             });
2468         }
2469         
2470         anc.cn.push(ctag);
2471         
2472         
2473         var cfg= {
2474             tag: 'li',
2475             cls: 'dropdown-menu-item',
2476             cn: [ anc ]
2477         };
2478         if (this.parent().type == 'treeview') {
2479             cfg.cls = 'treeview-menu';
2480         }
2481         if (this.active) {
2482             cfg.cls += ' active';
2483         }
2484         
2485         
2486         
2487         anc.href = this.href || cfg.cn[0].href ;
2488         ctag.html = this.html || cfg.cn[0].html ;
2489         return cfg;
2490     },
2491     
2492     initEvents: function()
2493     {
2494         if (this.parent().type == 'treeview') {
2495             this.el.select('a').on('click', this.onClick, this);
2496         }
2497         
2498         if (this.menu) {
2499             this.menu.parentType = this.xtype;
2500             this.menu.triggerEl = this.el;
2501             this.menu = this.addxtype(Roo.apply({}, this.menu));
2502         }
2503         
2504     },
2505     onClick : function(e)
2506     {
2507         Roo.log('item on click ');
2508         
2509         if(this.preventDefault){
2510             e.preventDefault();
2511         }
2512         //this.parent().hideMenuItems();
2513         
2514         this.fireEvent('click', this, e);
2515     },
2516     getEl : function()
2517     {
2518         return this.el;
2519     } 
2520 });
2521
2522  
2523
2524  /*
2525  * - LGPL
2526  *
2527  * menu separator
2528  * 
2529  */
2530
2531
2532 /**
2533  * @class Roo.bootstrap.MenuSeparator
2534  * @extends Roo.bootstrap.Component
2535  * Bootstrap MenuSeparator class
2536  * 
2537  * @constructor
2538  * Create a new MenuItem
2539  * @param {Object} config The config object
2540  */
2541
2542
2543 Roo.bootstrap.MenuSeparator = function(config){
2544     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2545 };
2546
2547 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2548     
2549     getAutoCreate : function(){
2550         var cfg = {
2551             cls: 'divider',
2552             tag : 'li'
2553         };
2554         
2555         return cfg;
2556     }
2557    
2558 });
2559
2560  
2561
2562  
2563 /*
2564 * Licence: LGPL
2565 */
2566
2567 /**
2568  * @class Roo.bootstrap.Modal
2569  * @extends Roo.bootstrap.Component
2570  * Bootstrap Modal class
2571  * @cfg {String} title Title of dialog
2572  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2573  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn
2574  * @cfg {Boolean} specificTitle default false
2575  * @cfg {Array} buttons Array of buttons or standard button set..
2576  * @cfg {String} buttonPosition (left|right|center) default right
2577  * @cfg {Boolean} animate default true
2578  * @cfg {Boolean} allow_close default true
2579  * @cfg {Boolean} fitwindow default false
2580  * @cfg {String} size (sm|lg) default empty
2581  * @cfg {Number} max_width set the max width of modal
2582  *
2583  *
2584  * @constructor
2585  * Create a new Modal Dialog
2586  * @param {Object} config The config object
2587  */
2588
2589 Roo.bootstrap.Modal = function(config){
2590     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2591     this.addEvents({
2592         // raw events
2593         /**
2594          * @event btnclick
2595          * The raw btnclick event for the button
2596          * @param {Roo.EventObject} e
2597          */
2598         "btnclick" : true,
2599         /**
2600          * @event resize
2601          * Fire when dialog resize
2602          * @param {Roo.bootstrap.Modal} this
2603          * @param {Roo.EventObject} e
2604          */
2605         "resize" : true
2606     });
2607     this.buttons = this.buttons || [];
2608
2609     if (this.tmpl) {
2610         this.tmpl = Roo.factory(this.tmpl);
2611     }
2612
2613 };
2614
2615 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2616
2617     title : 'test dialog',
2618
2619     buttons : false,
2620
2621     // set on load...
2622
2623     html: false,
2624
2625     tmp: false,
2626
2627     specificTitle: false,
2628
2629     buttonPosition: 'right',
2630
2631     allow_close : true,
2632
2633     animate : true,
2634
2635     fitwindow: false,
2636
2637
2638      // private
2639     dialogEl: false,
2640     bodyEl:  false,
2641     footerEl:  false,
2642     titleEl:  false,
2643     closeEl:  false,
2644
2645     size: '',
2646     
2647     max_width: 0,
2648
2649
2650     onRender : function(ct, position)
2651     {
2652         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2653
2654         if(!this.el){
2655             var cfg = Roo.apply({},  this.getAutoCreate());
2656             cfg.id = Roo.id();
2657             //if(!cfg.name){
2658             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2659             //}
2660             //if (!cfg.name.length) {
2661             //    delete cfg.name;
2662            // }
2663             if (this.cls) {
2664                 cfg.cls += ' ' + this.cls;
2665             }
2666             if (this.style) {
2667                 cfg.style = this.style;
2668             }
2669             this.el = Roo.get(document.body).createChild(cfg, position);
2670         }
2671         //var type = this.el.dom.type;
2672
2673
2674         if(this.tabIndex !== undefined){
2675             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2676         }
2677
2678         this.dialogEl = this.el.select('.modal-dialog',true).first();
2679         this.bodyEl = this.el.select('.modal-body',true).first();
2680         this.closeEl = this.el.select('.modal-header .close', true).first();
2681         this.headerEl = this.el.select('.modal-header',true).first();
2682         this.titleEl = this.el.select('.modal-title',true).first();
2683         this.footerEl = this.el.select('.modal-footer',true).first();
2684
2685         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2686         
2687         //this.el.addClass("x-dlg-modal");
2688
2689         if (this.buttons.length) {
2690             Roo.each(this.buttons, function(bb) {
2691                 var b = Roo.apply({}, bb);
2692                 b.xns = b.xns || Roo.bootstrap;
2693                 b.xtype = b.xtype || 'Button';
2694                 if (typeof(b.listeners) == 'undefined') {
2695                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2696                 }
2697
2698                 var btn = Roo.factory(b);
2699
2700                 btn.render(this.el.select('.modal-footer div').first());
2701
2702             },this);
2703         }
2704         // render the children.
2705         var nitems = [];
2706
2707         if(typeof(this.items) != 'undefined'){
2708             var items = this.items;
2709             delete this.items;
2710
2711             for(var i =0;i < items.length;i++) {
2712                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2713             }
2714         }
2715
2716         this.items = nitems;
2717
2718         // where are these used - they used to be body/close/footer
2719
2720
2721         this.initEvents();
2722         //this.el.addClass([this.fieldClass, this.cls]);
2723
2724     },
2725
2726     getAutoCreate : function()
2727     {
2728         var bdy = {
2729                 cls : 'modal-body',
2730                 html : this.html || ''
2731         };
2732
2733         var title = {
2734             tag: 'h4',
2735             cls : 'modal-title',
2736             html : this.title
2737         };
2738
2739         if(this.specificTitle){
2740             title = this.title;
2741
2742         };
2743
2744         var header = [];
2745         if (this.allow_close) {
2746             header.push({
2747                 tag: 'button',
2748                 cls : 'close',
2749                 html : '&times'
2750             });
2751         }
2752
2753         header.push(title);
2754
2755         var size = '';
2756
2757         if(this.size.length){
2758             size = 'modal-' + this.size;
2759         }
2760
2761         var modal = {
2762             cls: "modal",
2763              cn : [
2764                 {
2765                     cls: "modal-dialog " + size,
2766                     cn : [
2767                         {
2768                             cls : "modal-content",
2769                             cn : [
2770                                 {
2771                                     cls : 'modal-header',
2772                                     cn : header
2773                                 },
2774                                 bdy,
2775                                 {
2776                                     cls : 'modal-footer',
2777                                     cn : [
2778                                         {
2779                                             tag: 'div',
2780                                             cls: 'btn-' + this.buttonPosition
2781                                         }
2782                                     ]
2783
2784                                 }
2785
2786
2787                             ]
2788
2789                         }
2790                     ]
2791
2792                 }
2793             ]
2794         };
2795
2796         if(this.animate){
2797             modal.cls += ' fade';
2798         }
2799
2800         return modal;
2801
2802     },
2803     getChildContainer : function() {
2804
2805          return this.bodyEl;
2806
2807     },
2808     getButtonContainer : function() {
2809          return this.el.select('.modal-footer div',true).first();
2810
2811     },
2812     initEvents : function()
2813     {
2814         if (this.allow_close) {
2815             this.closeEl.on('click', this.hide, this);
2816         }
2817         Roo.EventManager.onWindowResize(this.resize, this, true);
2818
2819
2820     },
2821
2822     resize : function()
2823     {
2824         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),  Roo.lib.Dom.getViewHeight(true));
2825         
2826         if (this.fitwindow) {
2827             var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2828             var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2829             this.setSize(w,h);
2830         }
2831         
2832         if(!this.fitwindow && this.max_width !== 0){
2833             
2834             var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2835             var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2836             this.setSize(w,h);
2837         }
2838         
2839     },
2840
2841     setSize : function(w,h)
2842     {
2843         if (!w && !h) {
2844             return;
2845         }
2846         this.resizeTo(w,h);
2847     },
2848
2849     show : function() {
2850
2851         if (!this.rendered) {
2852             this.render();
2853         }
2854
2855         //this.el.setStyle('display', 'block');
2856         this.el.removeClass('hideing');        
2857         this.el.addClass('show');
2858  
2859         if(this.animate){  // element has 'fade'  - so stuff happens after .3s ?- not sure why the delay?
2860             var _this = this;
2861             (function(){
2862                 this.el.addClass('in');
2863             }).defer(50, this);
2864         }else{
2865             this.el.addClass('in');
2866         }
2867
2868         // not sure how we can show data in here..
2869         //if (this.tmpl) {
2870         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2871         //}
2872
2873         Roo.get(document.body).addClass("x-body-masked");
2874         
2875         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
2876         this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2877         this.maskEl.addClass('show');
2878         
2879         this.resize();
2880         
2881         this.fireEvent('show', this);
2882
2883         // set zindex here - otherwise it appears to be ignored...
2884         this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2885
2886         (function () {
2887             this.items.forEach( function(e) {
2888                 e.layout ? e.layout() : false;
2889
2890             });
2891         }).defer(100,this);
2892
2893     },
2894     hide : function()
2895     {
2896         if(this.fireEvent("beforehide", this) !== false){
2897             this.maskEl.removeClass('show');
2898             Roo.get(document.body).removeClass("x-body-masked");
2899             this.el.removeClass('in');
2900             this.el.select('.modal-dialog', true).first().setStyle('transform','');
2901
2902             if(this.animate){ // why
2903                 this.el.addClass('hideing');
2904                 (function(){
2905                     if (!this.el.hasClass('hideing')) {
2906                         return; // it's been shown again...
2907                     }
2908                     this.el.removeClass('show');
2909                     this.el.removeClass('hideing');
2910                 }).defer(150,this);
2911                 
2912             }else{
2913                  this.el.removeClass('show');
2914             }
2915             this.fireEvent('hide', this);
2916         }
2917     },
2918     isVisible : function()
2919     {
2920         
2921         return this.el.hasClass('show') && !this.el.hasClass('hideing');
2922         
2923     },
2924
2925     addButton : function(str, cb)
2926     {
2927
2928
2929         var b = Roo.apply({}, { html : str } );
2930         b.xns = b.xns || Roo.bootstrap;
2931         b.xtype = b.xtype || 'Button';
2932         if (typeof(b.listeners) == 'undefined') {
2933             b.listeners = { click : cb.createDelegate(this)  };
2934         }
2935
2936         var btn = Roo.factory(b);
2937
2938         btn.render(this.el.select('.modal-footer div').first());
2939
2940         return btn;
2941
2942     },
2943
2944     setDefaultButton : function(btn)
2945     {
2946         //this.el.select('.modal-footer').()
2947     },
2948     diff : false,
2949
2950     resizeTo: function(w,h)
2951     {
2952         // skip.. ?? why??
2953
2954         this.dialogEl.setWidth(w);
2955         if (this.diff === false) {
2956             this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2957         }
2958
2959         this.bodyEl.setHeight(h-this.diff);
2960
2961         this.fireEvent('resize', this);
2962
2963     },
2964     setContentSize  : function(w, h)
2965     {
2966
2967     },
2968     onButtonClick: function(btn,e)
2969     {
2970         //Roo.log([a,b,c]);
2971         this.fireEvent('btnclick', btn.name, e);
2972     },
2973      /**
2974      * Set the title of the Dialog
2975      * @param {String} str new Title
2976      */
2977     setTitle: function(str) {
2978         this.titleEl.dom.innerHTML = str;
2979     },
2980     /**
2981      * Set the body of the Dialog
2982      * @param {String} str new Title
2983      */
2984     setBody: function(str) {
2985         this.bodyEl.dom.innerHTML = str;
2986     },
2987     /**
2988      * Set the body of the Dialog using the template
2989      * @param {Obj} data - apply this data to the template and replace the body contents.
2990      */
2991     applyBody: function(obj)
2992     {
2993         if (!this.tmpl) {
2994             Roo.log("Error - using apply Body without a template");
2995             //code
2996         }
2997         this.tmpl.overwrite(this.bodyEl, obj);
2998     }
2999
3000 });
3001
3002
3003 Roo.apply(Roo.bootstrap.Modal,  {
3004     /**
3005          * Button config that displays a single OK button
3006          * @type Object
3007          */
3008         OK :  [{
3009             name : 'ok',
3010             weight : 'primary',
3011             html : 'OK'
3012         }],
3013         /**
3014          * Button config that displays Yes and No buttons
3015          * @type Object
3016          */
3017         YESNO : [
3018             {
3019                 name  : 'no',
3020                 html : 'No'
3021             },
3022             {
3023                 name  :'yes',
3024                 weight : 'primary',
3025                 html : 'Yes'
3026             }
3027         ],
3028
3029         /**
3030          * Button config that displays OK and Cancel buttons
3031          * @type Object
3032          */
3033         OKCANCEL : [
3034             {
3035                name : 'cancel',
3036                 html : 'Cancel'
3037             },
3038             {
3039                 name : 'ok',
3040                 weight : 'primary',
3041                 html : 'OK'
3042             }
3043         ],
3044         /**
3045          * Button config that displays Yes, No and Cancel buttons
3046          * @type Object
3047          */
3048         YESNOCANCEL : [
3049             {
3050                 name : 'yes',
3051                 weight : 'primary',
3052                 html : 'Yes'
3053             },
3054             {
3055                 name : 'no',
3056                 html : 'No'
3057             },
3058             {
3059                 name : 'cancel',
3060                 html : 'Cancel'
3061             }
3062         ],
3063         
3064         zIndex : 10001
3065 });
3066 /*
3067  * - LGPL
3068  *
3069  * messagebox - can be used as a replace
3070  * 
3071  */
3072 /**
3073  * @class Roo.MessageBox
3074  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
3075  * Example usage:
3076  *<pre><code>
3077 // Basic alert:
3078 Roo.Msg.alert('Status', 'Changes saved successfully.');
3079
3080 // Prompt for user data:
3081 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3082     if (btn == 'ok'){
3083         // process text value...
3084     }
3085 });
3086
3087 // Show a dialog using config options:
3088 Roo.Msg.show({
3089    title:'Save Changes?',
3090    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3091    buttons: Roo.Msg.YESNOCANCEL,
3092    fn: processResult,
3093    animEl: 'elId'
3094 });
3095 </code></pre>
3096  * @singleton
3097  */
3098 Roo.bootstrap.MessageBox = function(){
3099     var dlg, opt, mask, waitTimer;
3100     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3101     var buttons, activeTextEl, bwidth;
3102
3103     
3104     // private
3105     var handleButton = function(button){
3106         dlg.hide();
3107         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3108     };
3109
3110     // private
3111     var handleHide = function(){
3112         if(opt && opt.cls){
3113             dlg.el.removeClass(opt.cls);
3114         }
3115         //if(waitTimer){
3116         //    Roo.TaskMgr.stop(waitTimer);
3117         //    waitTimer = null;
3118         //}
3119     };
3120
3121     // private
3122     var updateButtons = function(b){
3123         var width = 0;
3124         if(!b){
3125             buttons["ok"].hide();
3126             buttons["cancel"].hide();
3127             buttons["yes"].hide();
3128             buttons["no"].hide();
3129             //dlg.footer.dom.style.display = 'none';
3130             return width;
3131         }
3132         dlg.footerEl.dom.style.display = '';
3133         for(var k in buttons){
3134             if(typeof buttons[k] != "function"){
3135                 if(b[k]){
3136                     buttons[k].show();
3137                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3138                     width += buttons[k].el.getWidth()+15;
3139                 }else{
3140                     buttons[k].hide();
3141                 }
3142             }
3143         }
3144         return width;
3145     };
3146
3147     // private
3148     var handleEsc = function(d, k, e){
3149         if(opt && opt.closable !== false){
3150             dlg.hide();
3151         }
3152         if(e){
3153             e.stopEvent();
3154         }
3155     };
3156
3157     return {
3158         /**
3159          * Returns a reference to the underlying {@link Roo.BasicDialog} element
3160          * @return {Roo.BasicDialog} The BasicDialog element
3161          */
3162         getDialog : function(){
3163            if(!dlg){
3164                 dlg = new Roo.bootstrap.Modal( {
3165                     //draggable: true,
3166                     //resizable:false,
3167                     //constraintoviewport:false,
3168                     //fixedcenter:true,
3169                     //collapsible : false,
3170                     //shim:true,
3171                     //modal: true,
3172                 //    width: 'auto',
3173                   //  height:100,
3174                     //buttonAlign:"center",
3175                     closeClick : function(){
3176                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3177                             handleButton("no");
3178                         }else{
3179                             handleButton("cancel");
3180                         }
3181                     }
3182                 });
3183                 dlg.render();
3184                 dlg.on("hide", handleHide);
3185                 mask = dlg.mask;
3186                 //dlg.addKeyListener(27, handleEsc);
3187                 buttons = {};
3188                 this.buttons = buttons;
3189                 var bt = this.buttonText;
3190                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3191                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3192                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3193                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3194                 //Roo.log(buttons);
3195                 bodyEl = dlg.bodyEl.createChild({
3196
3197                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3198                         '<textarea class="roo-mb-textarea"></textarea>' +
3199                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
3200                 });
3201                 msgEl = bodyEl.dom.firstChild;
3202                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3203                 textboxEl.enableDisplayMode();
3204                 textboxEl.addKeyListener([10,13], function(){
3205                     if(dlg.isVisible() && opt && opt.buttons){
3206                         if(opt.buttons.ok){
3207                             handleButton("ok");
3208                         }else if(opt.buttons.yes){
3209                             handleButton("yes");
3210                         }
3211                     }
3212                 });
3213                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3214                 textareaEl.enableDisplayMode();
3215                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3216                 progressEl.enableDisplayMode();
3217                 
3218                 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3219                 var pf = progressEl.dom.firstChild;
3220                 if (pf) {
3221                     pp = Roo.get(pf.firstChild);
3222                     pp.setHeight(pf.offsetHeight);
3223                 }
3224                 
3225             }
3226             return dlg;
3227         },
3228
3229         /**
3230          * Updates the message box body text
3231          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3232          * the XHTML-compliant non-breaking space character '&amp;#160;')
3233          * @return {Roo.MessageBox} This message box
3234          */
3235         updateText : function(text)
3236         {
3237             if(!dlg.isVisible() && !opt.width){
3238                 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3239                 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3240             }
3241             msgEl.innerHTML = text || '&#160;';
3242       
3243             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3244             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3245             var w = Math.max(
3246                     Math.min(opt.width || cw , this.maxWidth), 
3247                     Math.max(opt.minWidth || this.minWidth, bwidth)
3248             );
3249             if(opt.prompt){
3250                 activeTextEl.setWidth(w);
3251             }
3252             if(dlg.isVisible()){
3253                 dlg.fixedcenter = false;
3254             }
3255             // to big, make it scroll. = But as usual stupid IE does not support
3256             // !important..
3257             
3258             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3259                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3260                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3261             } else {
3262                 bodyEl.dom.style.height = '';
3263                 bodyEl.dom.style.overflowY = '';
3264             }
3265             if (cw > w) {
3266                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3267             } else {
3268                 bodyEl.dom.style.overflowX = '';
3269             }
3270             
3271             dlg.setContentSize(w, bodyEl.getHeight());
3272             if(dlg.isVisible()){
3273                 dlg.fixedcenter = true;
3274             }
3275             return this;
3276         },
3277
3278         /**
3279          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
3280          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3281          * @param {Number} value Any number between 0 and 1 (e.g., .5)
3282          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3283          * @return {Roo.MessageBox} This message box
3284          */
3285         updateProgress : function(value, text){
3286             if(text){
3287                 this.updateText(text);
3288             }
3289             
3290             if (pp) { // weird bug on my firefox - for some reason this is not defined
3291                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3292                 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3293             }
3294             return this;
3295         },        
3296
3297         /**
3298          * Returns true if the message box is currently displayed
3299          * @return {Boolean} True if the message box is visible, else false
3300          */
3301         isVisible : function(){
3302             return dlg && dlg.isVisible();  
3303         },
3304
3305         /**
3306          * Hides the message box if it is displayed
3307          */
3308         hide : function(){
3309             if(this.isVisible()){
3310                 dlg.hide();
3311             }  
3312         },
3313
3314         /**
3315          * Displays a new message box, or reinitializes an existing message box, based on the config options
3316          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3317          * The following config object properties are supported:
3318          * <pre>
3319 Property    Type             Description
3320 ----------  ---------------  ------------------------------------------------------------------------------------
3321 animEl            String/Element   An id or Element from which the message box should animate as it opens and
3322                                    closes (defaults to undefined)
3323 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3324                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
3325 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
3326                                    progress and wait dialogs will ignore this property and always hide the
3327                                    close button as they can only be closed programmatically.
3328 cls               String           A custom CSS class to apply to the message box element
3329 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
3330                                    displayed (defaults to 75)
3331 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
3332                                    function will be btn (the name of the button that was clicked, if applicable,
3333                                    e.g. "ok"), and text (the value of the active text field, if applicable).
3334                                    Progress and wait dialogs will ignore this option since they do not respond to
3335                                    user actions and can only be closed programmatically, so any required function
3336                                    should be called by the same code after it closes the dialog.
3337 icon              String           A CSS class that provides a background image to be used as an icon for
3338                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3339 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
3340 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
3341 modal             Boolean          False to allow user interaction with the page while the message box is
3342                                    displayed (defaults to true)
3343 msg               String           A string that will replace the existing message box body text (defaults
3344                                    to the XHTML-compliant non-breaking space character '&#160;')
3345 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
3346 progress          Boolean          True to display a progress bar (defaults to false)
3347 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
3348 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
3349 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
3350 title             String           The title text
3351 value             String           The string value to set into the active textbox element if displayed
3352 wait              Boolean          True to display a progress bar (defaults to false)
3353 width             Number           The width of the dialog in pixels
3354 </pre>
3355          *
3356          * Example usage:
3357          * <pre><code>
3358 Roo.Msg.show({
3359    title: 'Address',
3360    msg: 'Please enter your address:',
3361    width: 300,
3362    buttons: Roo.MessageBox.OKCANCEL,
3363    multiline: true,
3364    fn: saveAddress,
3365    animEl: 'addAddressBtn'
3366 });
3367 </code></pre>
3368          * @param {Object} config Configuration options
3369          * @return {Roo.MessageBox} This message box
3370          */
3371         show : function(options)
3372         {
3373             
3374             // this causes nightmares if you show one dialog after another
3375             // especially on callbacks..
3376              
3377             if(this.isVisible()){
3378                 
3379                 this.hide();
3380                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3381                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
3382                 Roo.log("New Dialog Message:" +  options.msg )
3383                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3384                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3385                 
3386             }
3387             var d = this.getDialog();
3388             opt = options;
3389             d.setTitle(opt.title || "&#160;");
3390             d.closeEl.setDisplayed(opt.closable !== false);
3391             activeTextEl = textboxEl;
3392             opt.prompt = opt.prompt || (opt.multiline ? true : false);
3393             if(opt.prompt){
3394                 if(opt.multiline){
3395                     textboxEl.hide();
3396                     textareaEl.show();
3397                     textareaEl.setHeight(typeof opt.multiline == "number" ?
3398                         opt.multiline : this.defaultTextHeight);
3399                     activeTextEl = textareaEl;
3400                 }else{
3401                     textboxEl.show();
3402                     textareaEl.hide();
3403                 }
3404             }else{
3405                 textboxEl.hide();
3406                 textareaEl.hide();
3407             }
3408             progressEl.setDisplayed(opt.progress === true);
3409             this.updateProgress(0);
3410             activeTextEl.dom.value = opt.value || "";
3411             if(opt.prompt){
3412                 dlg.setDefaultButton(activeTextEl);
3413             }else{
3414                 var bs = opt.buttons;
3415                 var db = null;
3416                 if(bs && bs.ok){
3417                     db = buttons["ok"];
3418                 }else if(bs && bs.yes){
3419                     db = buttons["yes"];
3420                 }
3421                 dlg.setDefaultButton(db);
3422             }
3423             bwidth = updateButtons(opt.buttons);
3424             this.updateText(opt.msg);
3425             if(opt.cls){
3426                 d.el.addClass(opt.cls);
3427             }
3428             d.proxyDrag = opt.proxyDrag === true;
3429             d.modal = opt.modal !== false;
3430             d.mask = opt.modal !== false ? mask : false;
3431             if(!d.isVisible()){
3432                 // force it to the end of the z-index stack so it gets a cursor in FF
3433                 document.body.appendChild(dlg.el.dom);
3434                 d.animateTarget = null;
3435                 d.show(options.animEl);
3436             }
3437             return this;
3438         },
3439
3440         /**
3441          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
3442          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3443          * and closing the message box when the process is complete.
3444          * @param {String} title The title bar text
3445          * @param {String} msg The message box body text
3446          * @return {Roo.MessageBox} This message box
3447          */
3448         progress : function(title, msg){
3449             this.show({
3450                 title : title,
3451                 msg : msg,
3452                 buttons: false,
3453                 progress:true,
3454                 closable:false,
3455                 minWidth: this.minProgressWidth,
3456                 modal : true
3457             });
3458             return this;
3459         },
3460
3461         /**
3462          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3463          * If a callback function is passed it will be called after the user clicks the button, and the
3464          * id of the button that was clicked will be passed as the only parameter to the callback
3465          * (could also be the top-right close button).
3466          * @param {String} title The title bar text
3467          * @param {String} msg The message box body text
3468          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3469          * @param {Object} scope (optional) The scope of the callback function
3470          * @return {Roo.MessageBox} This message box
3471          */
3472         alert : function(title, msg, fn, scope)
3473         {
3474             this.show({
3475                 title : title,
3476                 msg : msg,
3477                 buttons: this.OK,
3478                 fn: fn,
3479                 closable : false,
3480                 scope : scope,
3481                 modal : true
3482             });
3483             return this;
3484         },
3485
3486         /**
3487          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
3488          * interaction while waiting for a long-running process to complete that does not have defined intervals.
3489          * You are responsible for closing the message box when the process is complete.
3490          * @param {String} msg The message box body text
3491          * @param {String} title (optional) The title bar text
3492          * @return {Roo.MessageBox} This message box
3493          */
3494         wait : function(msg, title){
3495             this.show({
3496                 title : title,
3497                 msg : msg,
3498                 buttons: false,
3499                 closable:false,
3500                 progress:true,
3501                 modal:true,
3502                 width:300,
3503                 wait:true
3504             });
3505             waitTimer = Roo.TaskMgr.start({
3506                 run: function(i){
3507                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3508                 },
3509                 interval: 1000
3510             });
3511             return this;
3512         },
3513
3514         /**
3515          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3516          * If a callback function is passed it will be called after the user clicks either button, and the id of the
3517          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3518          * @param {String} title The title bar text
3519          * @param {String} msg The message box body text
3520          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3521          * @param {Object} scope (optional) The scope of the callback function
3522          * @return {Roo.MessageBox} This message box
3523          */
3524         confirm : function(title, msg, fn, scope){
3525             this.show({
3526                 title : title,
3527                 msg : msg,
3528                 buttons: this.YESNO,
3529                 fn: fn,
3530                 scope : scope,
3531                 modal : true
3532             });
3533             return this;
3534         },
3535
3536         /**
3537          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3538          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
3539          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3540          * (could also be the top-right close button) and the text that was entered will be passed as the two
3541          * parameters to the callback.
3542          * @param {String} title The title bar text
3543          * @param {String} msg The message box body text
3544          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3545          * @param {Object} scope (optional) The scope of the callback function
3546          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3547          * property, or the height in pixels to create the textbox (defaults to false / single-line)
3548          * @return {Roo.MessageBox} This message box
3549          */
3550         prompt : function(title, msg, fn, scope, multiline){
3551             this.show({
3552                 title : title,
3553                 msg : msg,
3554                 buttons: this.OKCANCEL,
3555                 fn: fn,
3556                 minWidth:250,
3557                 scope : scope,
3558                 prompt:true,
3559                 multiline: multiline,
3560                 modal : true
3561             });
3562             return this;
3563         },
3564
3565         /**
3566          * Button config that displays a single OK button
3567          * @type Object
3568          */
3569         OK : {ok:true},
3570         /**
3571          * Button config that displays Yes and No buttons
3572          * @type Object
3573          */
3574         YESNO : {yes:true, no:true},
3575         /**
3576          * Button config that displays OK and Cancel buttons
3577          * @type Object
3578          */
3579         OKCANCEL : {ok:true, cancel:true},
3580         /**
3581          * Button config that displays Yes, No and Cancel buttons
3582          * @type Object
3583          */
3584         YESNOCANCEL : {yes:true, no:true, cancel:true},
3585
3586         /**
3587          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3588          * @type Number
3589          */
3590         defaultTextHeight : 75,
3591         /**
3592          * The maximum width in pixels of the message box (defaults to 600)
3593          * @type Number
3594          */
3595         maxWidth : 600,
3596         /**
3597          * The minimum width in pixels of the message box (defaults to 100)
3598          * @type Number
3599          */
3600         minWidth : 100,
3601         /**
3602          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3603          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3604          * @type Number
3605          */
3606         minProgressWidth : 250,
3607         /**
3608          * An object containing the default button text strings that can be overriden for localized language support.
3609          * Supported properties are: ok, cancel, yes and no.
3610          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3611          * @type Object
3612          */
3613         buttonText : {
3614             ok : "OK",
3615             cancel : "Cancel",
3616             yes : "Yes",
3617             no : "No"
3618         }
3619     };
3620 }();
3621
3622 /**
3623  * Shorthand for {@link Roo.MessageBox}
3624  */
3625 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3626 Roo.Msg = Roo.Msg || Roo.MessageBox;
3627 /*
3628  * - LGPL
3629  *
3630  * navbar
3631  * 
3632  */
3633
3634 /**
3635  * @class Roo.bootstrap.Navbar
3636  * @extends Roo.bootstrap.Component
3637  * Bootstrap Navbar class
3638
3639  * @constructor
3640  * Create a new Navbar
3641  * @param {Object} config The config object
3642  */
3643
3644
3645 Roo.bootstrap.Navbar = function(config){
3646     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3647     this.addEvents({
3648         // raw events
3649         /**
3650          * @event beforetoggle
3651          * Fire before toggle the menu
3652          * @param {Roo.EventObject} e
3653          */
3654         "beforetoggle" : true
3655     });
3656 };
3657
3658 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3659     
3660     
3661    
3662     // private
3663     navItems : false,
3664     loadMask : false,
3665     
3666     
3667     getAutoCreate : function(){
3668         
3669         
3670         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3671         
3672     },
3673     
3674     initEvents :function ()
3675     {
3676         //Roo.log(this.el.select('.navbar-toggle',true));
3677         this.el.select('.navbar-toggle',true).on('click', function() {
3678             if(this.fireEvent('beforetoggle', this) !== false){
3679                this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3680             }
3681             
3682         }, this);
3683         
3684         var mark = {
3685             tag: "div",
3686             cls:"x-dlg-mask"
3687         };
3688         
3689         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3690         
3691         var size = this.el.getSize();
3692         this.maskEl.setSize(size.width, size.height);
3693         this.maskEl.enableDisplayMode("block");
3694         this.maskEl.hide();
3695         
3696         if(this.loadMask){
3697             this.maskEl.show();
3698         }
3699     },
3700     
3701     
3702     getChildContainer : function()
3703     {
3704         if (this.el.select('.collapse').getCount()) {
3705             return this.el.select('.collapse',true).first();
3706         }
3707         
3708         return this.el;
3709     },
3710     
3711     mask : function()
3712     {
3713         this.maskEl.show();
3714     },
3715     
3716     unmask : function()
3717     {
3718         this.maskEl.hide();
3719     } 
3720     
3721     
3722     
3723     
3724 });
3725
3726
3727
3728  
3729
3730  /*
3731  * - LGPL
3732  *
3733  * navbar
3734  * 
3735  */
3736
3737 /**
3738  * @class Roo.bootstrap.NavSimplebar
3739  * @extends Roo.bootstrap.Navbar
3740  * Bootstrap Sidebar class
3741  *
3742  * @cfg {Boolean} inverse is inverted color
3743  * 
3744  * @cfg {String} type (nav | pills | tabs)
3745  * @cfg {Boolean} arrangement stacked | justified
3746  * @cfg {String} align (left | right) alignment
3747  * 
3748  * @cfg {Boolean} main (true|false) main nav bar? default false
3749  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3750  * 
3751  * @cfg {String} tag (header|footer|nav|div) default is nav 
3752
3753  * 
3754  * 
3755  * 
3756  * @constructor
3757  * Create a new Sidebar
3758  * @param {Object} config The config object
3759  */
3760
3761
3762 Roo.bootstrap.NavSimplebar = function(config){
3763     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3764 };
3765
3766 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3767     
3768     inverse: false,
3769     
3770     type: false,
3771     arrangement: '',
3772     align : false,
3773     
3774     
3775     
3776     main : false,
3777     
3778     
3779     tag : false,
3780     
3781     
3782     getAutoCreate : function(){
3783         
3784         
3785         var cfg = {
3786             tag : this.tag || 'div',
3787             cls : 'navbar'
3788         };
3789           
3790         
3791         cfg.cn = [
3792             {
3793                 cls: 'nav',
3794                 tag : 'ul'
3795             }
3796         ];
3797         
3798          
3799         this.type = this.type || 'nav';
3800         if (['tabs','pills'].indexOf(this.type)!==-1) {
3801             cfg.cn[0].cls += ' nav-' + this.type
3802         
3803         
3804         } else {
3805             if (this.type!=='nav') {
3806                 Roo.log('nav type must be nav/tabs/pills')
3807             }
3808             cfg.cn[0].cls += ' navbar-nav'
3809         }
3810         
3811         
3812         
3813         
3814         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3815             cfg.cn[0].cls += ' nav-' + this.arrangement;
3816         }
3817         
3818         
3819         if (this.align === 'right') {
3820             cfg.cn[0].cls += ' navbar-right';
3821         }
3822         
3823         if (this.inverse) {
3824             cfg.cls += ' navbar-inverse';
3825             
3826         }
3827         
3828         
3829         return cfg;
3830     
3831         
3832     }
3833     
3834     
3835     
3836 });
3837
3838
3839
3840  
3841
3842  
3843        /*
3844  * - LGPL
3845  *
3846  * navbar
3847  * 
3848  */
3849
3850 /**
3851  * @class Roo.bootstrap.NavHeaderbar
3852  * @extends Roo.bootstrap.NavSimplebar
3853  * Bootstrap Sidebar class
3854  *
3855  * @cfg {String} brand what is brand
3856  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3857  * @cfg {String} brand_href href of the brand
3858  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3859  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3860  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3861  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3862  * 
3863  * @constructor
3864  * Create a new Sidebar
3865  * @param {Object} config The config object
3866  */
3867
3868
3869 Roo.bootstrap.NavHeaderbar = function(config){
3870     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3871       
3872 };
3873
3874 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3875     
3876     position: '',
3877     brand: '',
3878     brand_href: false,
3879     srButton : true,
3880     autohide : false,
3881     desktopCenter : false,
3882    
3883     
3884     getAutoCreate : function(){
3885         
3886         var   cfg = {
3887             tag: this.nav || 'nav',
3888             cls: 'navbar',
3889             role: 'navigation',
3890             cn: []
3891         };
3892         
3893         var cn = cfg.cn;
3894         if (this.desktopCenter) {
3895             cn.push({cls : 'container', cn : []});
3896             cn = cn[0].cn;
3897         }
3898         
3899         if(this.srButton){
3900             cn.push({
3901                 tag: 'div',
3902                 cls: 'navbar-header',
3903                 cn: [
3904                     {
3905                         tag: 'button',
3906                         type: 'button',
3907                         cls: 'navbar-toggle',
3908                         'data-toggle': 'collapse',
3909                         cn: [
3910                             {
3911                                 tag: 'span',
3912                                 cls: 'sr-only',
3913                                 html: 'Toggle navigation'
3914                             },
3915                             {
3916                                 tag: 'span',
3917                                 cls: 'icon-bar'
3918                             },
3919                             {
3920                                 tag: 'span',
3921                                 cls: 'icon-bar'
3922                             },
3923                             {
3924                                 tag: 'span',
3925                                 cls: 'icon-bar'
3926                             }
3927                         ]
3928                     }
3929                 ]
3930             });
3931         }
3932         
3933         cn.push({
3934             tag: 'div',
3935             cls: 'collapse navbar-collapse',
3936             cn : []
3937         });
3938         
3939         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3940         
3941         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3942             cfg.cls += ' navbar-' + this.position;
3943             
3944             // tag can override this..
3945             
3946             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3947         }
3948         
3949         if (this.brand !== '') {
3950             cn[0].cn.push({
3951                 tag: 'a',
3952                 href: this.brand_href ? this.brand_href : '#',
3953                 cls: 'navbar-brand',
3954                 cn: [
3955                 this.brand
3956                 ]
3957             });
3958         }
3959         
3960         if(this.main){
3961             cfg.cls += ' main-nav';
3962         }
3963         
3964         
3965         return cfg;
3966
3967         
3968     },
3969     getHeaderChildContainer : function()
3970     {
3971         if (this.srButton && this.el.select('.navbar-header').getCount()) {
3972             return this.el.select('.navbar-header',true).first();
3973         }
3974         
3975         return this.getChildContainer();
3976     },
3977     
3978     
3979     initEvents : function()
3980     {
3981         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3982         
3983         if (this.autohide) {
3984             
3985             var prevScroll = 0;
3986             var ft = this.el;
3987             
3988             Roo.get(document).on('scroll',function(e) {
3989                 var ns = Roo.get(document).getScroll().top;
3990                 var os = prevScroll;
3991                 prevScroll = ns;
3992                 
3993                 if(ns > os){
3994                     ft.removeClass('slideDown');
3995                     ft.addClass('slideUp');
3996                     return;
3997                 }
3998                 ft.removeClass('slideUp');
3999                 ft.addClass('slideDown');
4000                  
4001               
4002           },this);
4003         }
4004     }    
4005     
4006 });
4007
4008
4009
4010  
4011
4012  /*
4013  * - LGPL
4014  *
4015  * navbar
4016  * 
4017  */
4018
4019 /**
4020  * @class Roo.bootstrap.NavSidebar
4021  * @extends Roo.bootstrap.Navbar
4022  * Bootstrap Sidebar class
4023  * 
4024  * @constructor
4025  * Create a new Sidebar
4026  * @param {Object} config The config object
4027  */
4028
4029
4030 Roo.bootstrap.NavSidebar = function(config){
4031     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4032 };
4033
4034 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
4035     
4036     sidebar : true, // used by Navbar Item and NavbarGroup at present...
4037     
4038     getAutoCreate : function(){
4039         
4040         
4041         return  {
4042             tag: 'div',
4043             cls: 'sidebar sidebar-nav'
4044         };
4045     
4046         
4047     }
4048     
4049     
4050     
4051 });
4052
4053
4054
4055  
4056
4057  /*
4058  * - LGPL
4059  *
4060  * nav group
4061  * 
4062  */
4063
4064 /**
4065  * @class Roo.bootstrap.NavGroup
4066  * @extends Roo.bootstrap.Component
4067  * Bootstrap NavGroup class
4068  * @cfg {String} align (left|right)
4069  * @cfg {Boolean} inverse
4070  * @cfg {String} type (nav|pills|tab) default nav
4071  * @cfg {String} navId - reference Id for navbar.
4072
4073  * 
4074  * @constructor
4075  * Create a new nav group
4076  * @param {Object} config The config object
4077  */
4078
4079 Roo.bootstrap.NavGroup = function(config){
4080     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4081     this.navItems = [];
4082    
4083     Roo.bootstrap.NavGroup.register(this);
4084      this.addEvents({
4085         /**
4086              * @event changed
4087              * Fires when the active item changes
4088              * @param {Roo.bootstrap.NavGroup} this
4089              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4090              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
4091          */
4092         'changed': true
4093      });
4094     
4095 };
4096
4097 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
4098     
4099     align: '',
4100     inverse: false,
4101     form: false,
4102     type: 'nav',
4103     navId : '',
4104     // private
4105     
4106     navItems : false, 
4107     
4108     getAutoCreate : function()
4109     {
4110         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4111         
4112         cfg = {
4113             tag : 'ul',
4114             cls: 'nav' 
4115         };
4116         
4117         if (['tabs','pills'].indexOf(this.type)!==-1) {
4118             cfg.cls += ' nav-' + this.type
4119         } else {
4120             if (this.type!=='nav') {
4121                 Roo.log('nav type must be nav/tabs/pills')
4122             }
4123             cfg.cls += ' navbar-nav'
4124         }
4125         
4126         if (this.parent() && this.parent().sidebar) {
4127             cfg = {
4128                 tag: 'ul',
4129                 cls: 'dashboard-menu sidebar-menu'
4130             };
4131             
4132             return cfg;
4133         }
4134         
4135         if (this.form === true) {
4136             cfg = {
4137                 tag: 'form',
4138                 cls: 'navbar-form'
4139             };
4140             
4141             if (this.align === 'right') {
4142                 cfg.cls += ' navbar-right';
4143             } else {
4144                 cfg.cls += ' navbar-left';
4145             }
4146         }
4147         
4148         if (this.align === 'right') {
4149             cfg.cls += ' navbar-right';
4150         }
4151         
4152         if (this.inverse) {
4153             cfg.cls += ' navbar-inverse';
4154             
4155         }
4156         
4157         
4158         return cfg;
4159     },
4160     /**
4161     * sets the active Navigation item
4162     * @param {Roo.bootstrap.NavItem} the new current navitem
4163     */
4164     setActiveItem : function(item)
4165     {
4166         var prev = false;
4167         Roo.each(this.navItems, function(v){
4168             if (v == item) {
4169                 return ;
4170             }
4171             if (v.isActive()) {
4172                 v.setActive(false, true);
4173                 prev = v;
4174                 
4175             }
4176             
4177         });
4178
4179         item.setActive(true, true);
4180         this.fireEvent('changed', this, item, prev);
4181         
4182         
4183     },
4184     /**
4185     * gets the active Navigation item
4186     * @return {Roo.bootstrap.NavItem} the current navitem
4187     */
4188     getActive : function()
4189     {
4190         
4191         var prev = false;
4192         Roo.each(this.navItems, function(v){
4193             
4194             if (v.isActive()) {
4195                 prev = v;
4196                 
4197             }
4198             
4199         });
4200         return prev;
4201     },
4202     
4203     indexOfNav : function()
4204     {
4205         
4206         var prev = false;
4207         Roo.each(this.navItems, function(v,i){
4208             
4209             if (v.isActive()) {
4210                 prev = i;
4211                 
4212             }
4213             
4214         });
4215         return prev;
4216     },
4217     /**
4218     * adds a Navigation item
4219     * @param {Roo.bootstrap.NavItem} the navitem to add
4220     */
4221     addItem : function(cfg)
4222     {
4223         var cn = new Roo.bootstrap.NavItem(cfg);
4224         this.register(cn);
4225         cn.parentId = this.id;
4226         cn.onRender(this.el, null);
4227         return cn;
4228     },
4229     /**
4230     * register a Navigation item
4231     * @param {Roo.bootstrap.NavItem} the navitem to add
4232     */
4233     register : function(item)
4234     {
4235         this.navItems.push( item);
4236         item.navId = this.navId;
4237     
4238     },
4239     
4240     /**
4241     * clear all the Navigation item
4242     */
4243    
4244     clearAll : function()
4245     {
4246         this.navItems = [];
4247         this.el.dom.innerHTML = '';
4248     },
4249     
4250     getNavItem: function(tabId)
4251     {
4252         var ret = false;
4253         Roo.each(this.navItems, function(e) {
4254             if (e.tabId == tabId) {
4255                ret =  e;
4256                return false;
4257             }
4258             return true;
4259             
4260         });
4261         return ret;
4262     },
4263     
4264     setActiveNext : function()
4265     {
4266         var i = this.indexOfNav(this.getActive());
4267         if (i > this.navItems.length) {
4268             return;
4269         }
4270         this.setActiveItem(this.navItems[i+1]);
4271     },
4272     setActivePrev : function()
4273     {
4274         var i = this.indexOfNav(this.getActive());
4275         if (i  < 1) {
4276             return;
4277         }
4278         this.setActiveItem(this.navItems[i-1]);
4279     },
4280     clearWasActive : function(except) {
4281         Roo.each(this.navItems, function(e) {
4282             if (e.tabId != except.tabId && e.was_active) {
4283                e.was_active = false;
4284                return false;
4285             }
4286             return true;
4287             
4288         });
4289     },
4290     getWasActive : function ()
4291     {
4292         var r = false;
4293         Roo.each(this.navItems, function(e) {
4294             if (e.was_active) {
4295                r = e;
4296                return false;
4297             }
4298             return true;
4299             
4300         });
4301         return r;
4302     }
4303     
4304     
4305 });
4306
4307  
4308 Roo.apply(Roo.bootstrap.NavGroup, {
4309     
4310     groups: {},
4311      /**
4312     * register a Navigation Group
4313     * @param {Roo.bootstrap.NavGroup} the navgroup to add
4314     */
4315     register : function(navgrp)
4316     {
4317         this.groups[navgrp.navId] = navgrp;
4318         
4319     },
4320     /**
4321     * fetch a Navigation Group based on the navigation ID
4322     * @param {string} the navgroup to add
4323     * @returns {Roo.bootstrap.NavGroup} the navgroup 
4324     */
4325     get: function(navId) {
4326         if (typeof(this.groups[navId]) == 'undefined') {
4327             return false;
4328             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4329         }
4330         return this.groups[navId] ;
4331     }
4332     
4333     
4334     
4335 });
4336
4337  /*
4338  * - LGPL
4339  *
4340  * row
4341  * 
4342  */
4343
4344 /**
4345  * @class Roo.bootstrap.NavItem
4346  * @extends Roo.bootstrap.Component
4347  * Bootstrap Navbar.NavItem class
4348  * @cfg {String} href  link to
4349  * @cfg {String} html content of button
4350  * @cfg {String} badge text inside badge
4351  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4352  * @cfg {String} glyphicon name of glyphicon
4353  * @cfg {String} icon name of font awesome icon
4354  * @cfg {Boolean} active Is item active
4355  * @cfg {Boolean} disabled Is item disabled
4356  
4357  * @cfg {Boolean} preventDefault (true | false) default false
4358  * @cfg {String} tabId the tab that this item activates.
4359  * @cfg {String} tagtype (a|span) render as a href or span?
4360  * @cfg {Boolean} animateRef (true|false) link to element default false  
4361   
4362  * @constructor
4363  * Create a new Navbar Item
4364  * @param {Object} config The config object
4365  */
4366 Roo.bootstrap.NavItem = function(config){
4367     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4368     this.addEvents({
4369         // raw events
4370         /**
4371          * @event click
4372          * The raw click event for the entire grid.
4373          * @param {Roo.EventObject} e
4374          */
4375         "click" : true,
4376          /**
4377             * @event changed
4378             * Fires when the active item active state changes
4379             * @param {Roo.bootstrap.NavItem} this
4380             * @param {boolean} state the new state
4381              
4382          */
4383         'changed': true,
4384         /**
4385             * @event scrollto
4386             * Fires when scroll to element
4387             * @param {Roo.bootstrap.NavItem} this
4388             * @param {Object} options
4389             * @param {Roo.EventObject} e
4390              
4391          */
4392         'scrollto': true
4393     });
4394    
4395 };
4396
4397 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
4398     
4399     href: false,
4400     html: '',
4401     badge: '',
4402     icon: false,
4403     glyphicon: false,
4404     active: false,
4405     preventDefault : false,
4406     tabId : false,
4407     tagtype : 'a',
4408     disabled : false,
4409     animateRef : false,
4410     was_active : false,
4411     
4412     getAutoCreate : function(){
4413          
4414         var cfg = {
4415             tag: 'li',
4416             cls: 'nav-item'
4417             
4418         };
4419         
4420         if (this.active) {
4421             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4422         }
4423         if (this.disabled) {
4424             cfg.cls += ' disabled';
4425         }
4426         
4427         if (this.href || this.html || this.glyphicon || this.icon) {
4428             cfg.cn = [
4429                 {
4430                     tag: this.tagtype,
4431                     href : this.href || "#",
4432                     html: this.html || ''
4433                 }
4434             ];
4435             
4436             if (this.icon) {
4437                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4438             }
4439
4440             if(this.glyphicon) {
4441                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
4442             }
4443             
4444             if (this.menu) {
4445                 
4446                 cfg.cn[0].html += " <span class='caret'></span>";
4447              
4448             }
4449             
4450             if (this.badge !== '') {
4451                  
4452                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4453             }
4454         }
4455         
4456         
4457         
4458         return cfg;
4459     },
4460     initEvents: function() 
4461     {
4462         if (typeof (this.menu) != 'undefined') {
4463             this.menu.parentType = this.xtype;
4464             this.menu.triggerEl = this.el;
4465             this.menu = this.addxtype(Roo.apply({}, this.menu));
4466         }
4467         
4468         this.el.select('a',true).on('click', this.onClick, this);
4469         
4470         if(this.tagtype == 'span'){
4471             this.el.select('span',true).on('click', this.onClick, this);
4472         }
4473        
4474         // at this point parent should be available..
4475         this.parent().register(this);
4476     },
4477     
4478     onClick : function(e)
4479     {
4480         if (e.getTarget('.dropdown-menu-item')) {
4481             // did you click on a menu itemm.... - then don't trigger onclick..
4482             return;
4483         }
4484         
4485         if(
4486                 this.preventDefault || 
4487                 this.href == '#' 
4488         ){
4489             Roo.log("NavItem - prevent Default?");
4490             e.preventDefault();
4491         }
4492         
4493         if (this.disabled) {
4494             return;
4495         }
4496         
4497         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4498         if (tg && tg.transition) {
4499             Roo.log("waiting for the transitionend");
4500             return;
4501         }
4502         
4503         
4504         
4505         //Roo.log("fire event clicked");
4506         if(this.fireEvent('click', this, e) === false){
4507             return;
4508         };
4509         
4510         if(this.tagtype == 'span'){
4511             return;
4512         }
4513         
4514         //Roo.log(this.href);
4515         var ael = this.el.select('a',true).first();
4516         //Roo.log(ael);
4517         
4518         if(ael && this.animateRef && this.href.indexOf('#') > -1){
4519             //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4520             if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4521                 return; // ignore... - it's a 'hash' to another page.
4522             }
4523             Roo.log("NavItem - prevent Default?");
4524             e.preventDefault();
4525             this.scrollToElement(e);
4526         }
4527         
4528         
4529         var p =  this.parent();
4530    
4531         if (['tabs','pills'].indexOf(p.type)!==-1) {
4532             if (typeof(p.setActiveItem) !== 'undefined') {
4533                 p.setActiveItem(this);
4534             }
4535         }
4536         
4537         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4538         if (p.parentType == 'NavHeaderbar' && !this.menu) {
4539             // remove the collapsed menu expand...
4540             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
4541         }
4542     },
4543     
4544     isActive: function () {
4545         return this.active
4546     },
4547     setActive : function(state, fire, is_was_active)
4548     {
4549         if (this.active && !state && this.navId) {
4550             this.was_active = true;
4551             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4552             if (nv) {
4553                 nv.clearWasActive(this);
4554             }
4555             
4556         }
4557         this.active = state;
4558         
4559         if (!state ) {
4560             this.el.removeClass('active');
4561         } else if (!this.el.hasClass('active')) {
4562             this.el.addClass('active');
4563         }
4564         if (fire) {
4565             this.fireEvent('changed', this, state);
4566         }
4567         
4568         // show a panel if it's registered and related..
4569         
4570         if (!this.navId || !this.tabId || !state || is_was_active) {
4571             return;
4572         }
4573         
4574         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4575         if (!tg) {
4576             return;
4577         }
4578         var pan = tg.getPanelByName(this.tabId);
4579         if (!pan) {
4580             return;
4581         }
4582         // if we can not flip to new panel - go back to old nav highlight..
4583         if (false == tg.showPanel(pan)) {
4584             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4585             if (nv) {
4586                 var onav = nv.getWasActive();
4587                 if (onav) {
4588                     onav.setActive(true, false, true);
4589                 }
4590             }
4591             
4592         }
4593         
4594         
4595         
4596     },
4597      // this should not be here...
4598     setDisabled : function(state)
4599     {
4600         this.disabled = state;
4601         if (!state ) {
4602             this.el.removeClass('disabled');
4603         } else if (!this.el.hasClass('disabled')) {
4604             this.el.addClass('disabled');
4605         }
4606         
4607     },
4608     
4609     /**
4610      * Fetch the element to display the tooltip on.
4611      * @return {Roo.Element} defaults to this.el
4612      */
4613     tooltipEl : function()
4614     {
4615         return this.el.select('' + this.tagtype + '', true).first();
4616     },
4617     
4618     scrollToElement : function(e)
4619     {
4620         var c = document.body;
4621         
4622         /*
4623          * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4624          */
4625         if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4626             c = document.documentElement;
4627         }
4628         
4629         var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4630         
4631         if(!target){
4632             return;
4633         }
4634
4635         var o = target.calcOffsetsTo(c);
4636         
4637         var options = {
4638             target : target,
4639             value : o[1]
4640         };
4641         
4642         this.fireEvent('scrollto', this, options, e);
4643         
4644         Roo.get(c).scrollTo('top', options.value, true);
4645         
4646         return;
4647     }
4648 });
4649  
4650
4651  /*
4652  * - LGPL
4653  *
4654  * sidebar item
4655  *
4656  *  li
4657  *    <span> icon </span>
4658  *    <span> text </span>
4659  *    <span>badge </span>
4660  */
4661
4662 /**
4663  * @class Roo.bootstrap.NavSidebarItem
4664  * @extends Roo.bootstrap.NavItem
4665  * Bootstrap Navbar.NavSidebarItem class
4666  * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4667  * {Boolean} open is the menu open
4668  * {Boolean} buttonView use button as the tigger el rather that a (default false)
4669  * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4670  * {String} buttonSize (sm|md|lg)the extra classes for the button
4671  * {Boolean} showArrow show arrow next to the text (default true)
4672  * @constructor
4673  * Create a new Navbar Button
4674  * @param {Object} config The config object
4675  */
4676 Roo.bootstrap.NavSidebarItem = function(config){
4677     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4678     this.addEvents({
4679         // raw events
4680         /**
4681          * @event click
4682          * The raw click event for the entire grid.
4683          * @param {Roo.EventObject} e
4684          */
4685         "click" : true,
4686          /**
4687             * @event changed
4688             * Fires when the active item active state changes
4689             * @param {Roo.bootstrap.NavSidebarItem} this
4690             * @param {boolean} state the new state
4691              
4692          */
4693         'changed': true
4694     });
4695    
4696 };
4697
4698 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4699     
4700     badgeWeight : 'default',
4701     
4702     open: false,
4703     
4704     buttonView : false,
4705     
4706     buttonWeight : 'default',
4707     
4708     buttonSize : 'md',
4709     
4710     showArrow : true,
4711     
4712     getAutoCreate : function(){
4713         
4714         
4715         var a = {
4716                 tag: 'a',
4717                 href : this.href || '#',
4718                 cls: '',
4719                 html : '',
4720                 cn : []
4721         };
4722         
4723         if(this.buttonView){
4724             a = {
4725                 tag: 'button',
4726                 href : this.href || '#',
4727                 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4728                 html : this.html,
4729                 cn : []
4730             };
4731         }
4732         
4733         var cfg = {
4734             tag: 'li',
4735             cls: '',
4736             cn: [ a ]
4737         };
4738         
4739         if (this.active) {
4740             cfg.cls += ' active';
4741         }
4742         
4743         if (this.disabled) {
4744             cfg.cls += ' disabled';
4745         }
4746         if (this.open) {
4747             cfg.cls += ' open x-open';
4748         }
4749         // left icon..
4750         if (this.glyphicon || this.icon) {
4751             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4752             a.cn.push({ tag : 'i', cls : c }) ;
4753         }
4754         
4755         if(!this.buttonView){
4756             var span = {
4757                 tag: 'span',
4758                 html : this.html || ''
4759             };
4760
4761             a.cn.push(span);
4762             
4763         }
4764         
4765         if (this.badge !== '') {
4766             a.cn.push({ tag: 'span',  cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge }); 
4767         }
4768         
4769         if (this.menu) {
4770             
4771             if(this.showArrow){
4772                 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4773             }
4774             
4775             a.cls += ' dropdown-toggle treeview' ;
4776         }
4777         
4778         return cfg;
4779     },
4780     
4781     initEvents : function()
4782     { 
4783         if (typeof (this.menu) != 'undefined') {
4784             this.menu.parentType = this.xtype;
4785             this.menu.triggerEl = this.el;
4786             this.menu = this.addxtype(Roo.apply({}, this.menu));
4787         }
4788         
4789         this.el.on('click', this.onClick, this);
4790         
4791         if(this.badge !== ''){
4792             this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4793         }
4794         
4795     },
4796     
4797     onClick : function(e)
4798     {
4799         if(this.disabled){
4800             e.preventDefault();
4801             return;
4802         }
4803         
4804         if(this.preventDefault){
4805             e.preventDefault();
4806         }
4807         
4808         this.fireEvent('click', this);
4809     },
4810     
4811     disable : function()
4812     {
4813         this.setDisabled(true);
4814     },
4815     
4816     enable : function()
4817     {
4818         this.setDisabled(false);
4819     },
4820     
4821     setDisabled : function(state)
4822     {
4823         if(this.disabled == state){
4824             return;
4825         }
4826         
4827         this.disabled = state;
4828         
4829         if (state) {
4830             this.el.addClass('disabled');
4831             return;
4832         }
4833         
4834         this.el.removeClass('disabled');
4835         
4836         return;
4837     },
4838     
4839     setActive : function(state)
4840     {
4841         if(this.active == state){
4842             return;
4843         }
4844         
4845         this.active = state;
4846         
4847         if (state) {
4848             this.el.addClass('active');
4849             return;
4850         }
4851         
4852         this.el.removeClass('active');
4853         
4854         return;
4855     },
4856     
4857     isActive: function () 
4858     {
4859         return this.active;
4860     },
4861     
4862     setBadge : function(str)
4863     {
4864         if(!this.badgeEl){
4865             return;
4866         }
4867         
4868         this.badgeEl.dom.innerHTML = str;
4869     }
4870     
4871    
4872      
4873  
4874 });
4875  
4876
4877  /*
4878  * - LGPL
4879  *
4880  * row
4881  * 
4882  */
4883
4884 /**
4885  * @class Roo.bootstrap.Row
4886  * @extends Roo.bootstrap.Component
4887  * Bootstrap Row class (contains columns...)
4888  * 
4889  * @constructor
4890  * Create a new Row
4891  * @param {Object} config The config object
4892  */
4893
4894 Roo.bootstrap.Row = function(config){
4895     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4896 };
4897
4898 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4899     
4900     getAutoCreate : function(){
4901        return {
4902             cls: 'row clearfix'
4903        };
4904     }
4905     
4906     
4907 });
4908
4909  
4910
4911  /*
4912  * - LGPL
4913  *
4914  * element
4915  * 
4916  */
4917
4918 /**
4919  * @class Roo.bootstrap.Element
4920  * @extends Roo.bootstrap.Component
4921  * Bootstrap Element class
4922  * @cfg {String} html contents of the element
4923  * @cfg {String} tag tag of the element
4924  * @cfg {String} cls class of the element
4925  * @cfg {Boolean} preventDefault (true|false) default false
4926  * @cfg {Boolean} clickable (true|false) default false
4927  * 
4928  * @constructor
4929  * Create a new Element
4930  * @param {Object} config The config object
4931  */
4932
4933 Roo.bootstrap.Element = function(config){
4934     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4935     
4936     this.addEvents({
4937         // raw events
4938         /**
4939          * @event click
4940          * When a element is chick
4941          * @param {Roo.bootstrap.Element} this
4942          * @param {Roo.EventObject} e
4943          */
4944         "click" : true
4945     });
4946 };
4947
4948 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4949     
4950     tag: 'div',
4951     cls: '',
4952     html: '',
4953     preventDefault: false, 
4954     clickable: false,
4955     
4956     getAutoCreate : function(){
4957         
4958         var cfg = {
4959             tag: this.tag,
4960             // cls: this.cls, double assign in parent class Component.js :: onRender
4961             html: this.html
4962         };
4963         
4964         return cfg;
4965     },
4966     
4967     initEvents: function() 
4968     {
4969         Roo.bootstrap.Element.superclass.initEvents.call(this);
4970         
4971         if(this.clickable){
4972             this.el.on('click', this.onClick, this);
4973         }
4974         
4975     },
4976     
4977     onClick : function(e)
4978     {
4979         if(this.preventDefault){
4980             e.preventDefault();
4981         }
4982         
4983         this.fireEvent('click', this, e);
4984     },
4985     
4986     getValue : function()
4987     {
4988         return this.el.dom.innerHTML;
4989     },
4990     
4991     setValue : function(value)
4992     {
4993         this.el.dom.innerHTML = value;
4994     }
4995    
4996 });
4997
4998  
4999
5000  /*
5001  * - LGPL
5002  *
5003  * pagination
5004  * 
5005  */
5006
5007 /**
5008  * @class Roo.bootstrap.Pagination
5009  * @extends Roo.bootstrap.Component
5010  * Bootstrap Pagination class
5011  * @cfg {String} size xs | sm | md | lg
5012  * @cfg {Boolean} inverse false | true
5013  * 
5014  * @constructor
5015  * Create a new Pagination
5016  * @param {Object} config The config object
5017  */
5018
5019 Roo.bootstrap.Pagination = function(config){
5020     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5021 };
5022
5023 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
5024     
5025     cls: false,
5026     size: false,
5027     inverse: false,
5028     
5029     getAutoCreate : function(){
5030         var cfg = {
5031             tag: 'ul',
5032                 cls: 'pagination'
5033         };
5034         if (this.inverse) {
5035             cfg.cls += ' inverse';
5036         }
5037         if (this.html) {
5038             cfg.html=this.html;
5039         }
5040         if (this.cls) {
5041             cfg.cls += " " + this.cls;
5042         }
5043         return cfg;
5044     }
5045    
5046 });
5047
5048  
5049
5050  /*
5051  * - LGPL
5052  *
5053  * Pagination item
5054  * 
5055  */
5056
5057
5058 /**
5059  * @class Roo.bootstrap.PaginationItem
5060  * @extends Roo.bootstrap.Component
5061  * Bootstrap PaginationItem class
5062  * @cfg {String} html text
5063  * @cfg {String} href the link
5064  * @cfg {Boolean} preventDefault (true | false) default true
5065  * @cfg {Boolean} active (true | false) default false
5066  * @cfg {Boolean} disabled default false
5067  * 
5068  * 
5069  * @constructor
5070  * Create a new PaginationItem
5071  * @param {Object} config The config object
5072  */
5073
5074
5075 Roo.bootstrap.PaginationItem = function(config){
5076     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5077     this.addEvents({
5078         // raw events
5079         /**
5080          * @event click
5081          * The raw click event for the entire grid.
5082          * @param {Roo.EventObject} e
5083          */
5084         "click" : true
5085     });
5086 };
5087
5088 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
5089     
5090     href : false,
5091     html : false,
5092     preventDefault: true,
5093     active : false,
5094     cls : false,
5095     disabled: false,
5096     
5097     getAutoCreate : function(){
5098         var cfg= {
5099             tag: 'li',
5100             cn: [
5101                 {
5102                     tag : 'a',
5103                     href : this.href ? this.href : '#',
5104                     html : this.html ? this.html : ''
5105                 }
5106             ]
5107         };
5108         
5109         if(this.cls){
5110             cfg.cls = this.cls;
5111         }
5112         
5113         if(this.disabled){
5114             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5115         }
5116         
5117         if(this.active){
5118             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5119         }
5120         
5121         return cfg;
5122     },
5123     
5124     initEvents: function() {
5125         
5126         this.el.on('click', this.onClick, this);
5127         
5128     },
5129     onClick : function(e)
5130     {
5131         Roo.log('PaginationItem on click ');
5132         if(this.preventDefault){
5133             e.preventDefault();
5134         }
5135         
5136         if(this.disabled){
5137             return;
5138         }
5139         
5140         this.fireEvent('click', this, e);
5141     }
5142    
5143 });
5144
5145  
5146
5147  /*
5148  * - LGPL
5149  *
5150  * slider
5151  * 
5152  */
5153
5154
5155 /**
5156  * @class Roo.bootstrap.Slider
5157  * @extends Roo.bootstrap.Component
5158  * Bootstrap Slider class
5159  *    
5160  * @constructor
5161  * Create a new Slider
5162  * @param {Object} config The config object
5163  */
5164
5165 Roo.bootstrap.Slider = function(config){
5166     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5167 };
5168
5169 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
5170     
5171     getAutoCreate : function(){
5172         
5173         var cfg = {
5174             tag: 'div',
5175             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5176             cn: [
5177                 {
5178                     tag: 'a',
5179                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
5180                 }
5181             ]
5182         };
5183         
5184         return cfg;
5185     }
5186    
5187 });
5188
5189  /*
5190  * Based on:
5191  * Ext JS Library 1.1.1
5192  * Copyright(c) 2006-2007, Ext JS, LLC.
5193  *
5194  * Originally Released Under LGPL - original licence link has changed is not relivant.
5195  *
5196  * Fork - LGPL
5197  * <script type="text/javascript">
5198  */
5199  
5200
5201 /**
5202  * @class Roo.grid.ColumnModel
5203  * @extends Roo.util.Observable
5204  * This is the default implementation of a ColumnModel used by the Grid. It defines
5205  * the columns in the grid.
5206  * <br>Usage:<br>
5207  <pre><code>
5208  var colModel = new Roo.grid.ColumnModel([
5209         {header: "Ticker", width: 60, sortable: true, locked: true},
5210         {header: "Company Name", width: 150, sortable: true},
5211         {header: "Market Cap.", width: 100, sortable: true},
5212         {header: "$ Sales", width: 100, sortable: true, renderer: money},
5213         {header: "Employees", width: 100, sortable: true, resizable: false}
5214  ]);
5215  </code></pre>
5216  * <p>
5217  
5218  * The config options listed for this class are options which may appear in each
5219  * individual column definition.
5220  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5221  * @constructor
5222  * @param {Object} config An Array of column config objects. See this class's
5223  * config objects for details.
5224 */
5225 Roo.grid.ColumnModel = function(config){
5226         /**
5227      * The config passed into the constructor
5228      */
5229     this.config = config;
5230     this.lookup = {};
5231
5232     // if no id, create one
5233     // if the column does not have a dataIndex mapping,
5234     // map it to the order it is in the config
5235     for(var i = 0, len = config.length; i < len; i++){
5236         var c = config[i];
5237         if(typeof c.dataIndex == "undefined"){
5238             c.dataIndex = i;
5239         }
5240         if(typeof c.renderer == "string"){
5241             c.renderer = Roo.util.Format[c.renderer];
5242         }
5243         if(typeof c.id == "undefined"){
5244             c.id = Roo.id();
5245         }
5246         if(c.editor && c.editor.xtype){
5247             c.editor  = Roo.factory(c.editor, Roo.grid);
5248         }
5249         if(c.editor && c.editor.isFormField){
5250             c.editor = new Roo.grid.GridEditor(c.editor);
5251         }
5252         this.lookup[c.id] = c;
5253     }
5254
5255     /**
5256      * The width of columns which have no width specified (defaults to 100)
5257      * @type Number
5258      */
5259     this.defaultWidth = 100;
5260
5261     /**
5262      * Default sortable of columns which have no sortable specified (defaults to false)
5263      * @type Boolean
5264      */
5265     this.defaultSortable = false;
5266
5267     this.addEvents({
5268         /**
5269              * @event widthchange
5270              * Fires when the width of a column changes.
5271              * @param {ColumnModel} this
5272              * @param {Number} columnIndex The column index
5273              * @param {Number} newWidth The new width
5274              */
5275             "widthchange": true,
5276         /**
5277              * @event headerchange
5278              * Fires when the text of a header changes.
5279              * @param {ColumnModel} this
5280              * @param {Number} columnIndex The column index
5281              * @param {Number} newText The new header text
5282              */
5283             "headerchange": true,
5284         /**
5285              * @event hiddenchange
5286              * Fires when a column is hidden or "unhidden".
5287              * @param {ColumnModel} this
5288              * @param {Number} columnIndex The column index
5289              * @param {Boolean} hidden true if hidden, false otherwise
5290              */
5291             "hiddenchange": true,
5292             /**
5293          * @event columnmoved
5294          * Fires when a column is moved.
5295          * @param {ColumnModel} this
5296          * @param {Number} oldIndex
5297          * @param {Number} newIndex
5298          */
5299         "columnmoved" : true,
5300         /**
5301          * @event columlockchange
5302          * Fires when a column's locked state is changed
5303          * @param {ColumnModel} this
5304          * @param {Number} colIndex
5305          * @param {Boolean} locked true if locked
5306          */
5307         "columnlockchange" : true
5308     });
5309     Roo.grid.ColumnModel.superclass.constructor.call(this);
5310 };
5311 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5312     /**
5313      * @cfg {String} header The header text to display in the Grid view.
5314      */
5315     /**
5316      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5317      * {@link Roo.data.Record} definition from which to draw the column's value. If not
5318      * specified, the column's index is used as an index into the Record's data Array.
5319      */
5320     /**
5321      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5322      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5323      */
5324     /**
5325      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5326      * Defaults to the value of the {@link #defaultSortable} property.
5327      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5328      */
5329     /**
5330      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
5331      */
5332     /**
5333      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
5334      */
5335     /**
5336      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5337      */
5338     /**
5339      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5340      */
5341     /**
5342      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5343      * given the cell's data value. See {@link #setRenderer}. If not specified, the
5344      * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5345      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5346      */
5347        /**
5348      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
5349      */
5350     /**
5351      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
5352      */
5353     /**
5354      * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc).  Defaults to undefined.
5355      */
5356     /**
5357      * @cfg {String} cursor (Optional)
5358      */
5359     /**
5360      * @cfg {String} tooltip (Optional)
5361      */
5362     /**
5363      * @cfg {Number} xs (Optional)
5364      */
5365     /**
5366      * @cfg {Number} sm (Optional)
5367      */
5368     /**
5369      * @cfg {Number} md (Optional)
5370      */
5371     /**
5372      * @cfg {Number} lg (Optional)
5373      */
5374     /**
5375      * Returns the id of the column at the specified index.
5376      * @param {Number} index The column index
5377      * @return {String} the id
5378      */
5379     getColumnId : function(index){
5380         return this.config[index].id;
5381     },
5382
5383     /**
5384      * Returns the column for a specified id.
5385      * @param {String} id The column id
5386      * @return {Object} the column
5387      */
5388     getColumnById : function(id){
5389         return this.lookup[id];
5390     },
5391
5392     
5393     /**
5394      * Returns the column for a specified dataIndex.
5395      * @param {String} dataIndex The column dataIndex
5396      * @return {Object|Boolean} the column or false if not found
5397      */
5398     getColumnByDataIndex: function(dataIndex){
5399         var index = this.findColumnIndex(dataIndex);
5400         return index > -1 ? this.config[index] : false;
5401     },
5402     
5403     /**
5404      * Returns the index for a specified column id.
5405      * @param {String} id The column id
5406      * @return {Number} the index, or -1 if not found
5407      */
5408     getIndexById : function(id){
5409         for(var i = 0, len = this.config.length; i < len; i++){
5410             if(this.config[i].id == id){
5411                 return i;
5412             }
5413         }
5414         return -1;
5415     },
5416     
5417     /**
5418      * Returns the index for a specified column dataIndex.
5419      * @param {String} dataIndex The column dataIndex
5420      * @return {Number} the index, or -1 if not found
5421      */
5422     
5423     findColumnIndex : function(dataIndex){
5424         for(var i = 0, len = this.config.length; i < len; i++){
5425             if(this.config[i].dataIndex == dataIndex){
5426                 return i;
5427             }
5428         }
5429         return -1;
5430     },
5431     
5432     
5433     moveColumn : function(oldIndex, newIndex){
5434         var c = this.config[oldIndex];
5435         this.config.splice(oldIndex, 1);
5436         this.config.splice(newIndex, 0, c);
5437         this.dataMap = null;
5438         this.fireEvent("columnmoved", this, oldIndex, newIndex);
5439     },
5440
5441     isLocked : function(colIndex){
5442         return this.config[colIndex].locked === true;
5443     },
5444
5445     setLocked : function(colIndex, value, suppressEvent){
5446         if(this.isLocked(colIndex) == value){
5447             return;
5448         }
5449         this.config[colIndex].locked = value;
5450         if(!suppressEvent){
5451             this.fireEvent("columnlockchange", this, colIndex, value);
5452         }
5453     },
5454
5455     getTotalLockedWidth : function(){
5456         var totalWidth = 0;
5457         for(var i = 0; i < this.config.length; i++){
5458             if(this.isLocked(i) && !this.isHidden(i)){
5459                 this.totalWidth += this.getColumnWidth(i);
5460             }
5461         }
5462         return totalWidth;
5463     },
5464
5465     getLockedCount : function(){
5466         for(var i = 0, len = this.config.length; i < len; i++){
5467             if(!this.isLocked(i)){
5468                 return i;
5469             }
5470         }
5471         
5472         return this.config.length;
5473     },
5474
5475     /**
5476      * Returns the number of columns.
5477      * @return {Number}
5478      */
5479     getColumnCount : function(visibleOnly){
5480         if(visibleOnly === true){
5481             var c = 0;
5482             for(var i = 0, len = this.config.length; i < len; i++){
5483                 if(!this.isHidden(i)){
5484                     c++;
5485                 }
5486             }
5487             return c;
5488         }
5489         return this.config.length;
5490     },
5491
5492     /**
5493      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5494      * @param {Function} fn
5495      * @param {Object} scope (optional)
5496      * @return {Array} result
5497      */
5498     getColumnsBy : function(fn, scope){
5499         var r = [];
5500         for(var i = 0, len = this.config.length; i < len; i++){
5501             var c = this.config[i];
5502             if(fn.call(scope||this, c, i) === true){
5503                 r[r.length] = c;
5504             }
5505         }
5506         return r;
5507     },
5508
5509     /**
5510      * Returns true if the specified column is sortable.
5511      * @param {Number} col The column index
5512      * @return {Boolean}
5513      */
5514     isSortable : function(col){
5515         if(typeof this.config[col].sortable == "undefined"){
5516             return this.defaultSortable;
5517         }
5518         return this.config[col].sortable;
5519     },
5520
5521     /**
5522      * Returns the rendering (formatting) function defined for the column.
5523      * @param {Number} col The column index.
5524      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5525      */
5526     getRenderer : function(col){
5527         if(!this.config[col].renderer){
5528             return Roo.grid.ColumnModel.defaultRenderer;
5529         }
5530         return this.config[col].renderer;
5531     },
5532
5533     /**
5534      * Sets the rendering (formatting) function for a column.
5535      * @param {Number} col The column index
5536      * @param {Function} fn The function to use to process the cell's raw data
5537      * to return HTML markup for the grid view. The render function is called with
5538      * the following parameters:<ul>
5539      * <li>Data value.</li>
5540      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5541      * <li>css A CSS style string to apply to the table cell.</li>
5542      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5543      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5544      * <li>Row index</li>
5545      * <li>Column index</li>
5546      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5547      */
5548     setRenderer : function(col, fn){
5549         this.config[col].renderer = fn;
5550     },
5551
5552     /**
5553      * Returns the width for the specified column.
5554      * @param {Number} col The column index
5555      * @return {Number}
5556      */
5557     getColumnWidth : function(col){
5558         return this.config[col].width * 1 || this.defaultWidth;
5559     },
5560
5561     /**
5562      * Sets the width for a column.
5563      * @param {Number} col The column index
5564      * @param {Number} width The new width
5565      */
5566     setColumnWidth : function(col, width, suppressEvent){
5567         this.config[col].width = width;
5568         this.totalWidth = null;
5569         if(!suppressEvent){
5570              this.fireEvent("widthchange", this, col, width);
5571         }
5572     },
5573
5574     /**
5575      * Returns the total width of all columns.
5576      * @param {Boolean} includeHidden True to include hidden column widths
5577      * @return {Number}
5578      */
5579     getTotalWidth : function(includeHidden){
5580         if(!this.totalWidth){
5581             this.totalWidth = 0;
5582             for(var i = 0, len = this.config.length; i < len; i++){
5583                 if(includeHidden || !this.isHidden(i)){
5584                     this.totalWidth += this.getColumnWidth(i);
5585                 }
5586             }
5587         }
5588         return this.totalWidth;
5589     },
5590
5591     /**
5592      * Returns the header for the specified column.
5593      * @param {Number} col The column index
5594      * @return {String}
5595      */
5596     getColumnHeader : function(col){
5597         return this.config[col].header;
5598     },
5599
5600     /**
5601      * Sets the header for a column.
5602      * @param {Number} col The column index
5603      * @param {String} header The new header
5604      */
5605     setColumnHeader : function(col, header){
5606         this.config[col].header = header;
5607         this.fireEvent("headerchange", this, col, header);
5608     },
5609
5610     /**
5611      * Returns the tooltip for the specified column.
5612      * @param {Number} col The column index
5613      * @return {String}
5614      */
5615     getColumnTooltip : function(col){
5616             return this.config[col].tooltip;
5617     },
5618     /**
5619      * Sets the tooltip for a column.
5620      * @param {Number} col The column index
5621      * @param {String} tooltip The new tooltip
5622      */
5623     setColumnTooltip : function(col, tooltip){
5624             this.config[col].tooltip = tooltip;
5625     },
5626
5627     /**
5628      * Returns the dataIndex for the specified column.
5629      * @param {Number} col The column index
5630      * @return {Number}
5631      */
5632     getDataIndex : function(col){
5633         return this.config[col].dataIndex;
5634     },
5635
5636     /**
5637      * Sets the dataIndex for a column.
5638      * @param {Number} col The column index
5639      * @param {Number} dataIndex The new dataIndex
5640      */
5641     setDataIndex : function(col, dataIndex){
5642         this.config[col].dataIndex = dataIndex;
5643     },
5644
5645     
5646     
5647     /**
5648      * Returns true if the cell is editable.
5649      * @param {Number} colIndex The column index
5650      * @param {Number} rowIndex The row index - this is nto actually used..?
5651      * @return {Boolean}
5652      */
5653     isCellEditable : function(colIndex, rowIndex){
5654         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5655     },
5656
5657     /**
5658      * Returns the editor defined for the cell/column.
5659      * return false or null to disable editing.
5660      * @param {Number} colIndex The column index
5661      * @param {Number} rowIndex The row index
5662      * @return {Object}
5663      */
5664     getCellEditor : function(colIndex, rowIndex){
5665         return this.config[colIndex].editor;
5666     },
5667
5668     /**
5669      * Sets if a column is editable.
5670      * @param {Number} col The column index
5671      * @param {Boolean} editable True if the column is editable
5672      */
5673     setEditable : function(col, editable){
5674         this.config[col].editable = editable;
5675     },
5676
5677
5678     /**
5679      * Returns true if the column is hidden.
5680      * @param {Number} colIndex The column index
5681      * @return {Boolean}
5682      */
5683     isHidden : function(colIndex){
5684         return this.config[colIndex].hidden;
5685     },
5686
5687
5688     /**
5689      * Returns true if the column width cannot be changed
5690      */
5691     isFixed : function(colIndex){
5692         return this.config[colIndex].fixed;
5693     },
5694
5695     /**
5696      * Returns true if the column can be resized
5697      * @return {Boolean}
5698      */
5699     isResizable : function(colIndex){
5700         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5701     },
5702     /**
5703      * Sets if a column is hidden.
5704      * @param {Number} colIndex The column index
5705      * @param {Boolean} hidden True if the column is hidden
5706      */
5707     setHidden : function(colIndex, hidden){
5708         this.config[colIndex].hidden = hidden;
5709         this.totalWidth = null;
5710         this.fireEvent("hiddenchange", this, colIndex, hidden);
5711     },
5712
5713     /**
5714      * Sets the editor for a column.
5715      * @param {Number} col The column index
5716      * @param {Object} editor The editor object
5717      */
5718     setEditor : function(col, editor){
5719         this.config[col].editor = editor;
5720     }
5721 });
5722
5723 Roo.grid.ColumnModel.defaultRenderer = function(value)
5724 {
5725     if(typeof value == "object") {
5726         return value;
5727     }
5728         if(typeof value == "string" && value.length < 1){
5729             return "&#160;";
5730         }
5731     
5732         return String.format("{0}", value);
5733 };
5734
5735 // Alias for backwards compatibility
5736 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5737 /*
5738  * Based on:
5739  * Ext JS Library 1.1.1
5740  * Copyright(c) 2006-2007, Ext JS, LLC.
5741  *
5742  * Originally Released Under LGPL - original licence link has changed is not relivant.
5743  *
5744  * Fork - LGPL
5745  * <script type="text/javascript">
5746  */
5747  
5748 /**
5749  * @class Roo.LoadMask
5750  * A simple utility class for generically masking elements while loading data.  If the element being masked has
5751  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5752  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
5753  * element's UpdateManager load indicator and will be destroyed after the initial load.
5754  * @constructor
5755  * Create a new LoadMask
5756  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5757  * @param {Object} config The config object
5758  */
5759 Roo.LoadMask = function(el, config){
5760     this.el = Roo.get(el);
5761     Roo.apply(this, config);
5762     if(this.store){
5763         this.store.on('beforeload', this.onBeforeLoad, this);
5764         this.store.on('load', this.onLoad, this);
5765         this.store.on('loadexception', this.onLoadException, this);
5766         this.removeMask = false;
5767     }else{
5768         var um = this.el.getUpdateManager();
5769         um.showLoadIndicator = false; // disable the default indicator
5770         um.on('beforeupdate', this.onBeforeLoad, this);
5771         um.on('update', this.onLoad, this);
5772         um.on('failure', this.onLoad, this);
5773         this.removeMask = true;
5774     }
5775 };
5776
5777 Roo.LoadMask.prototype = {
5778     /**
5779      * @cfg {Boolean} removeMask
5780      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5781      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
5782      */
5783     /**
5784      * @cfg {String} msg
5785      * The text to display in a centered loading message box (defaults to 'Loading...')
5786      */
5787     msg : 'Loading...',
5788     /**
5789      * @cfg {String} msgCls
5790      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5791      */
5792     msgCls : 'x-mask-loading',
5793
5794     /**
5795      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5796      * @type Boolean
5797      */
5798     disabled: false,
5799
5800     /**
5801      * Disables the mask to prevent it from being displayed
5802      */
5803     disable : function(){
5804        this.disabled = true;
5805     },
5806
5807     /**
5808      * Enables the mask so that it can be displayed
5809      */
5810     enable : function(){
5811         this.disabled = false;
5812     },
5813     
5814     onLoadException : function()
5815     {
5816         Roo.log(arguments);
5817         
5818         if (typeof(arguments[3]) != 'undefined') {
5819             Roo.MessageBox.alert("Error loading",arguments[3]);
5820         } 
5821         /*
5822         try {
5823             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5824                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5825             }   
5826         } catch(e) {
5827             
5828         }
5829         */
5830     
5831         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5832     },
5833     // private
5834     onLoad : function()
5835     {
5836         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5837     },
5838
5839     // private
5840     onBeforeLoad : function(){
5841         if(!this.disabled){
5842             (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5843         }
5844     },
5845
5846     // private
5847     destroy : function(){
5848         if(this.store){
5849             this.store.un('beforeload', this.onBeforeLoad, this);
5850             this.store.un('load', this.onLoad, this);
5851             this.store.un('loadexception', this.onLoadException, this);
5852         }else{
5853             var um = this.el.getUpdateManager();
5854             um.un('beforeupdate', this.onBeforeLoad, this);
5855             um.un('update', this.onLoad, this);
5856             um.un('failure', this.onLoad, this);
5857         }
5858     }
5859 };/*
5860  * - LGPL
5861  *
5862  * table
5863  * 
5864  */
5865
5866 /**
5867  * @class Roo.bootstrap.Table
5868  * @extends Roo.bootstrap.Component
5869  * Bootstrap Table class
5870  * @cfg {String} cls table class
5871  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5872  * @cfg {String} bgcolor Specifies the background color for a table
5873  * @cfg {Number} border Specifies whether the table cells should have borders or not
5874  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5875  * @cfg {Number} cellspacing Specifies the space between cells
5876  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5877  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5878  * @cfg {String} sortable Specifies that the table should be sortable
5879  * @cfg {String} summary Specifies a summary of the content of a table
5880  * @cfg {Number} width Specifies the width of a table
5881  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5882  * 
5883  * @cfg {boolean} striped Should the rows be alternative striped
5884  * @cfg {boolean} bordered Add borders to the table
5885  * @cfg {boolean} hover Add hover highlighting
5886  * @cfg {boolean} condensed Format condensed
5887  * @cfg {boolean} responsive Format condensed
5888  * @cfg {Boolean} loadMask (true|false) default false
5889  * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5890  * @cfg {Boolean} headerShow (true|false) generate thead, default true
5891  * @cfg {Boolean} rowSelection (true|false) default false
5892  * @cfg {Boolean} cellSelection (true|false) default false
5893  * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5894  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5895  * @cfg {Boolean} lazyLoad  auto load data while scrolling to the end (default false)
5896  * @cfg {Boolean} auto_hide_footer  auto hide footer if only one page (default false)
5897  
5898  * 
5899  * @constructor
5900  * Create a new Table
5901  * @param {Object} config The config object
5902  */
5903
5904 Roo.bootstrap.Table = function(config){
5905     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5906     
5907   
5908     
5909     // BC...
5910     this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5911     this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5912     this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5913     this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5914     
5915     this.sm = this.sm || {xtype: 'RowSelectionModel'};
5916     if (this.sm) {
5917         this.sm.grid = this;
5918         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5919         this.sm = this.selModel;
5920         this.sm.xmodule = this.xmodule || false;
5921     }
5922     
5923     if (this.cm && typeof(this.cm.config) == 'undefined') {
5924         this.colModel = new Roo.grid.ColumnModel(this.cm);
5925         this.cm = this.colModel;
5926         this.cm.xmodule = this.xmodule || false;
5927     }
5928     if (this.store) {
5929         this.store= Roo.factory(this.store, Roo.data);
5930         this.ds = this.store;
5931         this.ds.xmodule = this.xmodule || false;
5932          
5933     }
5934     if (this.footer && this.store) {
5935         this.footer.dataSource = this.ds;
5936         this.footer = Roo.factory(this.footer);
5937     }
5938     
5939     /** @private */
5940     this.addEvents({
5941         /**
5942          * @event cellclick
5943          * Fires when a cell is clicked
5944          * @param {Roo.bootstrap.Table} this
5945          * @param {Roo.Element} el
5946          * @param {Number} rowIndex
5947          * @param {Number} columnIndex
5948          * @param {Roo.EventObject} e
5949          */
5950         "cellclick" : true,
5951         /**
5952          * @event celldblclick
5953          * Fires when a cell is double clicked
5954          * @param {Roo.bootstrap.Table} this
5955          * @param {Roo.Element} el
5956          * @param {Number} rowIndex
5957          * @param {Number} columnIndex
5958          * @param {Roo.EventObject} e
5959          */
5960         "celldblclick" : true,
5961         /**
5962          * @event rowclick
5963          * Fires when a row is clicked
5964          * @param {Roo.bootstrap.Table} this
5965          * @param {Roo.Element} el
5966          * @param {Number} rowIndex
5967          * @param {Roo.EventObject} e
5968          */
5969         "rowclick" : true,
5970         /**
5971          * @event rowdblclick
5972          * Fires when a row is double clicked
5973          * @param {Roo.bootstrap.Table} this
5974          * @param {Roo.Element} el
5975          * @param {Number} rowIndex
5976          * @param {Roo.EventObject} e
5977          */
5978         "rowdblclick" : true,
5979         /**
5980          * @event mouseover
5981          * Fires when a mouseover occur
5982          * @param {Roo.bootstrap.Table} this
5983          * @param {Roo.Element} el
5984          * @param {Number} rowIndex
5985          * @param {Number} columnIndex
5986          * @param {Roo.EventObject} e
5987          */
5988         "mouseover" : true,
5989         /**
5990          * @event mouseout
5991          * Fires when a mouseout occur
5992          * @param {Roo.bootstrap.Table} this
5993          * @param {Roo.Element} el
5994          * @param {Number} rowIndex
5995          * @param {Number} columnIndex
5996          * @param {Roo.EventObject} e
5997          */
5998         "mouseout" : true,
5999         /**
6000          * @event rowclass
6001          * Fires when a row is rendered, so you can change add a style to it.
6002          * @param {Roo.bootstrap.Table} this
6003          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
6004          */
6005         'rowclass' : true,
6006           /**
6007          * @event rowsrendered
6008          * Fires when all the  rows have been rendered
6009          * @param {Roo.bootstrap.Table} this
6010          */
6011         'rowsrendered' : true,
6012         /**
6013          * @event contextmenu
6014          * The raw contextmenu event for the entire grid.
6015          * @param {Roo.EventObject} e
6016          */
6017         "contextmenu" : true,
6018         /**
6019          * @event rowcontextmenu
6020          * Fires when a row is right clicked
6021          * @param {Roo.bootstrap.Table} this
6022          * @param {Number} rowIndex
6023          * @param {Roo.EventObject} e
6024          */
6025         "rowcontextmenu" : true,
6026         /**
6027          * @event cellcontextmenu
6028          * Fires when a cell is right clicked
6029          * @param {Roo.bootstrap.Table} this
6030          * @param {Number} rowIndex
6031          * @param {Number} cellIndex
6032          * @param {Roo.EventObject} e
6033          */
6034          "cellcontextmenu" : true,
6035          /**
6036          * @event headercontextmenu
6037          * Fires when a header is right clicked
6038          * @param {Roo.bootstrap.Table} this
6039          * @param {Number} columnIndex
6040          * @param {Roo.EventObject} e
6041          */
6042         "headercontextmenu" : true
6043     });
6044 };
6045
6046 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
6047     
6048     cls: false,
6049     align: false,
6050     bgcolor: false,
6051     border: false,
6052     cellpadding: false,
6053     cellspacing: false,
6054     frame: false,
6055     rules: false,
6056     sortable: false,
6057     summary: false,
6058     width: false,
6059     striped : false,
6060     scrollBody : false,
6061     bordered: false,
6062     hover:  false,
6063     condensed : false,
6064     responsive : false,
6065     sm : false,
6066     cm : false,
6067     store : false,
6068     loadMask : false,
6069     footerShow : true,
6070     headerShow : true,
6071   
6072     rowSelection : false,
6073     cellSelection : false,
6074     layout : false,
6075     
6076     // Roo.Element - the tbody
6077     mainBody: false,
6078     // Roo.Element - thead element
6079     mainHead: false,
6080     
6081     container: false, // used by gridpanel...
6082     
6083     lazyLoad : false,
6084     
6085     CSS : Roo.util.CSS,
6086     
6087     auto_hide_footer : false,
6088     
6089     getAutoCreate : function()
6090     {
6091         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6092         
6093         cfg = {
6094             tag: 'table',
6095             cls : 'table',
6096             cn : []
6097         };
6098         if (this.scrollBody) {
6099             cfg.cls += ' table-body-fixed';
6100         }    
6101         if (this.striped) {
6102             cfg.cls += ' table-striped';
6103         }
6104         
6105         if (this.hover) {
6106             cfg.cls += ' table-hover';
6107         }
6108         if (this.bordered) {
6109             cfg.cls += ' table-bordered';
6110         }
6111         if (this.condensed) {
6112             cfg.cls += ' table-condensed';
6113         }
6114         if (this.responsive) {
6115             cfg.cls += ' table-responsive';
6116         }
6117         
6118         if (this.cls) {
6119             cfg.cls+=  ' ' +this.cls;
6120         }
6121         
6122         // this lot should be simplifed...
6123         var _t = this;
6124         var cp = [
6125             'align',
6126             'bgcolor',
6127             'border',
6128             'cellpadding',
6129             'cellspacing',
6130             'frame',
6131             'rules',
6132             'sortable',
6133             'summary',
6134             'width'
6135         ].forEach(function(k) {
6136             if (_t[k]) {
6137                 cfg[k] = _t[k];
6138             }
6139         });
6140         
6141         
6142         if (this.layout) {
6143             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6144         }
6145         
6146         if(this.store || this.cm){
6147             if(this.headerShow){
6148                 cfg.cn.push(this.renderHeader());
6149             }
6150             
6151             cfg.cn.push(this.renderBody());
6152             
6153             if(this.footerShow){
6154                 cfg.cn.push(this.renderFooter());
6155             }
6156             // where does this come from?
6157             //cfg.cls+=  ' TableGrid';
6158         }
6159         
6160         return { cn : [ cfg ] };
6161     },
6162     
6163     initEvents : function()
6164     {   
6165         if(!this.store || !this.cm){
6166             return;
6167         }
6168         if (this.selModel) {
6169             this.selModel.initEvents();
6170         }
6171         
6172         
6173         //Roo.log('initEvents with ds!!!!');
6174         
6175         this.mainBody = this.el.select('tbody', true).first();
6176         this.mainHead = this.el.select('thead', true).first();
6177         this.mainFoot = this.el.select('tfoot', true).first();
6178         
6179         
6180         
6181         var _this = this;
6182         
6183         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6184             e.on('click', _this.sort, _this);
6185         });
6186         
6187         this.mainBody.on("click", this.onClick, this);
6188         this.mainBody.on("dblclick", this.onDblClick, this);
6189         
6190         // why is this done????? = it breaks dialogs??
6191         //this.parent().el.setStyle('position', 'relative');
6192         
6193         
6194         if (this.footer) {
6195             this.footer.parentId = this.id;
6196             this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6197             
6198             if(this.lazyLoad){
6199                 this.el.select('tfoot tr td').first().addClass('hide');
6200             }
6201         } 
6202         
6203         if(this.loadMask) {
6204             this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6205         }
6206         
6207         this.store.on('load', this.onLoad, this);
6208         this.store.on('beforeload', this.onBeforeLoad, this);
6209         this.store.on('update', this.onUpdate, this);
6210         this.store.on('add', this.onAdd, this);
6211         this.store.on("clear", this.clear, this);
6212         
6213         this.el.on("contextmenu", this.onContextMenu, this);
6214         
6215         this.mainBody.on('scroll', this.onBodyScroll, this);
6216         
6217         this.cm.on("headerchange", this.onHeaderChange, this);
6218         
6219         this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6220         
6221     },
6222     
6223     onContextMenu : function(e, t)
6224     {
6225         this.processEvent("contextmenu", e);
6226     },
6227     
6228     processEvent : function(name, e)
6229     {
6230         if (name != 'touchstart' ) {
6231             this.fireEvent(name, e);    
6232         }
6233         
6234         var t = e.getTarget();
6235         
6236         var cell = Roo.get(t);
6237         
6238         if(!cell){
6239             return;
6240         }
6241         
6242         if(cell.findParent('tfoot', false, true)){
6243             return;
6244         }
6245         
6246         if(cell.findParent('thead', false, true)){
6247             
6248             if(e.getTarget().nodeName.toLowerCase() != 'th'){
6249                 cell = Roo.get(t).findParent('th', false, true);
6250                 if (!cell) {
6251                     Roo.log("failed to find th in thead?");
6252                     Roo.log(e.getTarget());
6253                     return;
6254                 }
6255             }
6256             
6257             var cellIndex = cell.dom.cellIndex;
6258             
6259             var ename = name == 'touchstart' ? 'click' : name;
6260             this.fireEvent("header" + ename, this, cellIndex, e);
6261             
6262             return;
6263         }
6264         
6265         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6266             cell = Roo.get(t).findParent('td', false, true);
6267             if (!cell) {
6268                 Roo.log("failed to find th in tbody?");
6269                 Roo.log(e.getTarget());
6270                 return;
6271             }
6272         }
6273         
6274         var row = cell.findParent('tr', false, true);
6275         var cellIndex = cell.dom.cellIndex;
6276         var rowIndex = row.dom.rowIndex - 1;
6277         
6278         if(row !== false){
6279             
6280             this.fireEvent("row" + name, this, rowIndex, e);
6281             
6282             if(cell !== false){
6283             
6284                 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6285             }
6286         }
6287         
6288     },
6289     
6290     onMouseover : function(e, el)
6291     {
6292         var cell = Roo.get(el);
6293         
6294         if(!cell){
6295             return;
6296         }
6297         
6298         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6299             cell = cell.findParent('td', false, true);
6300         }
6301         
6302         var row = cell.findParent('tr', false, true);
6303         var cellIndex = cell.dom.cellIndex;
6304         var rowIndex = row.dom.rowIndex - 1; // start from 0
6305         
6306         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6307         
6308     },
6309     
6310     onMouseout : function(e, el)
6311     {
6312         var cell = Roo.get(el);
6313         
6314         if(!cell){
6315             return;
6316         }
6317         
6318         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6319             cell = cell.findParent('td', false, true);
6320         }
6321         
6322         var row = cell.findParent('tr', false, true);
6323         var cellIndex = cell.dom.cellIndex;
6324         var rowIndex = row.dom.rowIndex - 1; // start from 0
6325         
6326         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6327         
6328     },
6329     
6330     onClick : function(e, el)
6331     {
6332         var cell = Roo.get(el);
6333         
6334         if(!cell || (!this.cellSelection && !this.rowSelection)){
6335             return;
6336         }
6337         
6338         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6339             cell = cell.findParent('td', false, true);
6340         }
6341         
6342         if(!cell || typeof(cell) == 'undefined'){
6343             return;
6344         }
6345         
6346         var row = cell.findParent('tr', false, true);
6347         
6348         if(!row || typeof(row) == 'undefined'){
6349             return;
6350         }
6351         
6352         var cellIndex = cell.dom.cellIndex;
6353         var rowIndex = this.getRowIndex(row);
6354         
6355         // why??? - should these not be based on SelectionModel?
6356         if(this.cellSelection){
6357             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6358         }
6359         
6360         if(this.rowSelection){
6361             this.fireEvent('rowclick', this, row, rowIndex, e);
6362         }
6363         
6364         
6365     },
6366         
6367     onDblClick : function(e,el)
6368     {
6369         var cell = Roo.get(el);
6370         
6371         if(!cell || (!this.cellSelection && !this.rowSelection)){
6372             return;
6373         }
6374         
6375         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6376             cell = cell.findParent('td', false, true);
6377         }
6378         
6379         if(!cell || typeof(cell) == 'undefined'){
6380             return;
6381         }
6382         
6383         var row = cell.findParent('tr', false, true);
6384         
6385         if(!row || typeof(row) == 'undefined'){
6386             return;
6387         }
6388         
6389         var cellIndex = cell.dom.cellIndex;
6390         var rowIndex = this.getRowIndex(row);
6391         
6392         if(this.cellSelection){
6393             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6394         }
6395         
6396         if(this.rowSelection){
6397             this.fireEvent('rowdblclick', this, row, rowIndex, e);
6398         }
6399     },
6400     
6401     sort : function(e,el)
6402     {
6403         var col = Roo.get(el);
6404         
6405         if(!col.hasClass('sortable')){
6406             return;
6407         }
6408         
6409         var sort = col.attr('sort');
6410         var dir = 'ASC';
6411         
6412         if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6413             dir = 'DESC';
6414         }
6415         
6416         this.store.sortInfo = {field : sort, direction : dir};
6417         
6418         if (this.footer) {
6419             Roo.log("calling footer first");
6420             this.footer.onClick('first');
6421         } else {
6422         
6423             this.store.load({ params : { start : 0 } });
6424         }
6425     },
6426     
6427     renderHeader : function()
6428     {
6429         var header = {
6430             tag: 'thead',
6431             cn : []
6432         };
6433         
6434         var cm = this.cm;
6435         this.totalWidth = 0;
6436         
6437         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6438             
6439             var config = cm.config[i];
6440             
6441             var c = {
6442                 tag: 'th',
6443                 cls : 'x-hcol-' + i,
6444                 style : '',
6445                 html: cm.getColumnHeader(i)
6446             };
6447             
6448             var hh = '';
6449             
6450             if(typeof(config.sortable) != 'undefined' && config.sortable){
6451                 c.cls = 'sortable';
6452                 c.html = '<i class="glyphicon"></i>' + c.html;
6453             }
6454             
6455             if(typeof(config.lgHeader) != 'undefined'){
6456                 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6457             }
6458             
6459             if(typeof(config.mdHeader) != 'undefined'){
6460                 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6461             }
6462             
6463             if(typeof(config.smHeader) != 'undefined'){
6464                 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6465             }
6466             
6467             if(typeof(config.xsHeader) != 'undefined'){
6468                 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6469             }
6470             
6471             if(hh.length){
6472                 c.html = hh;
6473             }
6474             
6475             if(typeof(config.tooltip) != 'undefined'){
6476                 c.tooltip = config.tooltip;
6477             }
6478             
6479             if(typeof(config.colspan) != 'undefined'){
6480                 c.colspan = config.colspan;
6481             }
6482             
6483             if(typeof(config.hidden) != 'undefined' && config.hidden){
6484                 c.style += ' display:none;';
6485             }
6486             
6487             if(typeof(config.dataIndex) != 'undefined'){
6488                 c.sort = config.dataIndex;
6489             }
6490             
6491            
6492             
6493             if(typeof(config.align) != 'undefined' && config.align.length){
6494                 c.style += ' text-align:' + config.align + ';';
6495             }
6496             
6497             if(typeof(config.width) != 'undefined'){
6498                 c.style += ' width:' + config.width + 'px;';
6499                 this.totalWidth += config.width;
6500             } else {
6501                 this.totalWidth += 100; // assume minimum of 100 per column?
6502             }
6503             
6504             if(typeof(config.cls) != 'undefined'){
6505                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6506             }
6507             
6508             ['xs','sm','md','lg'].map(function(size){
6509                 
6510                 if(typeof(config[size]) == 'undefined'){
6511                     return;
6512                 }
6513                 
6514                 if (!config[size]) { // 0 = hidden
6515                     c.cls += ' hidden-' + size;
6516                     return;
6517                 }
6518                 
6519                 c.cls += ' col-' + size + '-' + config[size];
6520
6521             });
6522             
6523             header.cn.push(c)
6524         }
6525         
6526         return header;
6527     },
6528     
6529     renderBody : function()
6530     {
6531         var body = {
6532             tag: 'tbody',
6533             cn : [
6534                 {
6535                     tag: 'tr',
6536                     cn : [
6537                         {
6538                             tag : 'td',
6539                             colspan :  this.cm.getColumnCount()
6540                         }
6541                     ]
6542                 }
6543             ]
6544         };
6545         
6546         return body;
6547     },
6548     
6549     renderFooter : function()
6550     {
6551         var footer = {
6552             tag: 'tfoot',
6553             cn : [
6554                 {
6555                     tag: 'tr',
6556                     cn : [
6557                         {
6558                             tag : 'td',
6559                             colspan :  this.cm.getColumnCount()
6560                         }
6561                     ]
6562                 }
6563             ]
6564         };
6565         
6566         return footer;
6567     },
6568     
6569     
6570     
6571     onLoad : function()
6572     {
6573 //        Roo.log('ds onload');
6574         this.clear();
6575         
6576         var _this = this;
6577         var cm = this.cm;
6578         var ds = this.store;
6579         
6580         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6581             e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6582             if (_this.store.sortInfo) {
6583                     
6584                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6585                     e.select('i', true).addClass(['glyphicon-arrow-up']);
6586                 }
6587                 
6588                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6589                     e.select('i', true).addClass(['glyphicon-arrow-down']);
6590                 }
6591             }
6592         });
6593         
6594         var tbody =  this.mainBody;
6595               
6596         if(ds.getCount() > 0){
6597             ds.data.each(function(d,rowIndex){
6598                 var row =  this.renderRow(cm, ds, rowIndex);
6599                 
6600                 tbody.createChild(row);
6601                 
6602                 var _this = this;
6603                 
6604                 if(row.cellObjects.length){
6605                     Roo.each(row.cellObjects, function(r){
6606                         _this.renderCellObject(r);
6607                     })
6608                 }
6609                 
6610             }, this);
6611         }
6612         
6613         var tfoot = this.el.select('tfoot', true).first();
6614         
6615         if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6616             
6617             this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6618             
6619             var total = this.ds.getTotalCount();
6620             
6621             if(this.footer.pageSize < total){
6622                 this.mainFoot.show();
6623             }
6624         }
6625         
6626         Roo.each(this.el.select('tbody td', true).elements, function(e){
6627             e.on('mouseover', _this.onMouseover, _this);
6628         });
6629         
6630         Roo.each(this.el.select('tbody td', true).elements, function(e){
6631             e.on('mouseout', _this.onMouseout, _this);
6632         });
6633         this.fireEvent('rowsrendered', this);
6634         
6635         this.autoSize();
6636     },
6637     
6638     
6639     onUpdate : function(ds,record)
6640     {
6641         this.refreshRow(record);
6642         this.autoSize();
6643     },
6644     
6645     onRemove : function(ds, record, index, isUpdate){
6646         if(isUpdate !== true){
6647             this.fireEvent("beforerowremoved", this, index, record);
6648         }
6649         var bt = this.mainBody.dom;
6650         
6651         var rows = this.el.select('tbody > tr', true).elements;
6652         
6653         if(typeof(rows[index]) != 'undefined'){
6654             bt.removeChild(rows[index].dom);
6655         }
6656         
6657 //        if(bt.rows[index]){
6658 //            bt.removeChild(bt.rows[index]);
6659 //        }
6660         
6661         if(isUpdate !== true){
6662             //this.stripeRows(index);
6663             //this.syncRowHeights(index, index);
6664             //this.layout();
6665             this.fireEvent("rowremoved", this, index, record);
6666         }
6667     },
6668     
6669     onAdd : function(ds, records, rowIndex)
6670     {
6671         //Roo.log('on Add called');
6672         // - note this does not handle multiple adding very well..
6673         var bt = this.mainBody.dom;
6674         for (var i =0 ; i < records.length;i++) {
6675             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6676             //Roo.log(records[i]);
6677             //Roo.log(this.store.getAt(rowIndex+i));
6678             this.insertRow(this.store, rowIndex + i, false);
6679             return;
6680         }
6681         
6682     },
6683     
6684     
6685     refreshRow : function(record){
6686         var ds = this.store, index;
6687         if(typeof record == 'number'){
6688             index = record;
6689             record = ds.getAt(index);
6690         }else{
6691             index = ds.indexOf(record);
6692         }
6693         this.insertRow(ds, index, true);
6694         this.autoSize();
6695         this.onRemove(ds, record, index+1, true);
6696         this.autoSize();
6697         //this.syncRowHeights(index, index);
6698         //this.layout();
6699         this.fireEvent("rowupdated", this, index, record);
6700     },
6701     
6702     insertRow : function(dm, rowIndex, isUpdate){
6703         
6704         if(!isUpdate){
6705             this.fireEvent("beforerowsinserted", this, rowIndex);
6706         }
6707             //var s = this.getScrollState();
6708         var row = this.renderRow(this.cm, this.store, rowIndex);
6709         // insert before rowIndex..
6710         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6711         
6712         var _this = this;
6713                 
6714         if(row.cellObjects.length){
6715             Roo.each(row.cellObjects, function(r){
6716                 _this.renderCellObject(r);
6717             })
6718         }
6719             
6720         if(!isUpdate){
6721             this.fireEvent("rowsinserted", this, rowIndex);
6722             //this.syncRowHeights(firstRow, lastRow);
6723             //this.stripeRows(firstRow);
6724             //this.layout();
6725         }
6726         
6727     },
6728     
6729     
6730     getRowDom : function(rowIndex)
6731     {
6732         var rows = this.el.select('tbody > tr', true).elements;
6733         
6734         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6735         
6736     },
6737     // returns the object tree for a tr..
6738   
6739     
6740     renderRow : function(cm, ds, rowIndex) 
6741     {
6742         var d = ds.getAt(rowIndex);
6743         
6744         var row = {
6745             tag : 'tr',
6746             cls : 'x-row-' + rowIndex,
6747             cn : []
6748         };
6749             
6750         var cellObjects = [];
6751         
6752         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6753             var config = cm.config[i];
6754             
6755             var renderer = cm.getRenderer(i);
6756             var value = '';
6757             var id = false;
6758             
6759             if(typeof(renderer) !== 'undefined'){
6760                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6761             }
6762             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6763             // and are rendered into the cells after the row is rendered - using the id for the element.
6764             
6765             if(typeof(value) === 'object'){
6766                 id = Roo.id();
6767                 cellObjects.push({
6768                     container : id,
6769                     cfg : value 
6770                 })
6771             }
6772             
6773             var rowcfg = {
6774                 record: d,
6775                 rowIndex : rowIndex,
6776                 colIndex : i,
6777                 rowClass : ''
6778             };
6779
6780             this.fireEvent('rowclass', this, rowcfg);
6781             
6782             var td = {
6783                 tag: 'td',
6784                 cls : rowcfg.rowClass + ' x-col-' + i,
6785                 style: '',
6786                 html: (typeof(value) === 'object') ? '' : value
6787             };
6788             
6789             if (id) {
6790                 td.id = id;
6791             }
6792             
6793             if(typeof(config.colspan) != 'undefined'){
6794                 td.colspan = config.colspan;
6795             }
6796             
6797             if(typeof(config.hidden) != 'undefined' && config.hidden){
6798                 td.style += ' display:none;';
6799             }
6800             
6801             if(typeof(config.align) != 'undefined' && config.align.length){
6802                 td.style += ' text-align:' + config.align + ';';
6803             }
6804             if(typeof(config.valign) != 'undefined' && config.valign.length){
6805                 td.style += ' vertical-align:' + config.valign + ';';
6806             }
6807             
6808             if(typeof(config.width) != 'undefined'){
6809                 td.style += ' width:' +  config.width + 'px;';
6810             }
6811             
6812             if(typeof(config.cursor) != 'undefined'){
6813                 td.style += ' cursor:' +  config.cursor + ';';
6814             }
6815             
6816             if(typeof(config.cls) != 'undefined'){
6817                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6818             }
6819             
6820             ['xs','sm','md','lg'].map(function(size){
6821                 
6822                 if(typeof(config[size]) == 'undefined'){
6823                     return;
6824                 }
6825                 
6826                 if (!config[size]) { // 0 = hidden
6827                     td.cls += ' hidden-' + size;
6828                     return;
6829                 }
6830                 
6831                 td.cls += ' col-' + size + '-' + config[size];
6832
6833             });
6834             
6835             row.cn.push(td);
6836            
6837         }
6838         
6839         row.cellObjects = cellObjects;
6840         
6841         return row;
6842           
6843     },
6844     
6845     
6846     
6847     onBeforeLoad : function()
6848     {
6849         
6850     },
6851      /**
6852      * Remove all rows
6853      */
6854     clear : function()
6855     {
6856         this.el.select('tbody', true).first().dom.innerHTML = '';
6857     },
6858     /**
6859      * Show or hide a row.
6860      * @param {Number} rowIndex to show or hide
6861      * @param {Boolean} state hide
6862      */
6863     setRowVisibility : function(rowIndex, state)
6864     {
6865         var bt = this.mainBody.dom;
6866         
6867         var rows = this.el.select('tbody > tr', true).elements;
6868         
6869         if(typeof(rows[rowIndex]) == 'undefined'){
6870             return;
6871         }
6872         rows[rowIndex].dom.style.display = state ? '' : 'none';
6873     },
6874     
6875     
6876     getSelectionModel : function(){
6877         if(!this.selModel){
6878             this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6879         }
6880         return this.selModel;
6881     },
6882     /*
6883      * Render the Roo.bootstrap object from renderder
6884      */
6885     renderCellObject : function(r)
6886     {
6887         var _this = this;
6888         
6889         r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6890         
6891         var t = r.cfg.render(r.container);
6892         
6893         if(r.cfg.cn){
6894             Roo.each(r.cfg.cn, function(c){
6895                 var child = {
6896                     container: t.getChildContainer(),
6897                     cfg: c
6898                 };
6899                 _this.renderCellObject(child);
6900             })
6901         }
6902     },
6903     
6904     getRowIndex : function(row)
6905     {
6906         var rowIndex = -1;
6907         
6908         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6909             if(el != row){
6910                 return;
6911             }
6912             
6913             rowIndex = index;
6914         });
6915         
6916         return rowIndex;
6917     },
6918      /**
6919      * Returns the grid's underlying element = used by panel.Grid
6920      * @return {Element} The element
6921      */
6922     getGridEl : function(){
6923         return this.el;
6924     },
6925      /**
6926      * Forces a resize - used by panel.Grid
6927      * @return {Element} The element
6928      */
6929     autoSize : function()
6930     {
6931         //var ctr = Roo.get(this.container.dom.parentElement);
6932         var ctr = Roo.get(this.el.dom);
6933         
6934         var thd = this.getGridEl().select('thead',true).first();
6935         var tbd = this.getGridEl().select('tbody', true).first();
6936         var tfd = this.getGridEl().select('tfoot', true).first();
6937         
6938         var cw = ctr.getWidth();
6939         
6940         if (tbd) {
6941             
6942             tbd.setSize(ctr.getWidth(),
6943                         ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6944             );
6945             var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6946             cw -= barsize;
6947         }
6948         cw = Math.max(cw, this.totalWidth);
6949         this.getGridEl().select('tr',true).setWidth(cw);
6950         // resize 'expandable coloumn?
6951         
6952         return; // we doe not have a view in this design..
6953         
6954     },
6955     onBodyScroll: function()
6956     {
6957         //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6958         if(this.mainHead){
6959             this.mainHead.setStyle({
6960                 'position' : 'relative',
6961                 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6962             });
6963         }
6964         
6965         if(this.lazyLoad){
6966             
6967             var scrollHeight = this.mainBody.dom.scrollHeight;
6968             
6969             var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6970             
6971             var height = this.mainBody.getHeight();
6972             
6973             if(scrollHeight - height == scrollTop) {
6974                 
6975                 var total = this.ds.getTotalCount();
6976                 
6977                 if(this.footer.cursor + this.footer.pageSize < total){
6978                     
6979                     this.footer.ds.load({
6980                         params : {
6981                             start : this.footer.cursor + this.footer.pageSize,
6982                             limit : this.footer.pageSize
6983                         },
6984                         add : true
6985                     });
6986                 }
6987             }
6988             
6989         }
6990     },
6991     
6992     onHeaderChange : function()
6993     {
6994         var header = this.renderHeader();
6995         var table = this.el.select('table', true).first();
6996         
6997         this.mainHead.remove();
6998         this.mainHead = table.createChild(header, this.mainBody, false);
6999     },
7000     
7001     onHiddenChange : function(colModel, colIndex, hidden)
7002     {
7003         var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7004         var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7005         
7006         this.CSS.updateRule(thSelector, "display", "");
7007         this.CSS.updateRule(tdSelector, "display", "");
7008         
7009         if(hidden){
7010             this.CSS.updateRule(thSelector, "display", "none");
7011             this.CSS.updateRule(tdSelector, "display", "none");
7012         }
7013         
7014         this.onHeaderChange();
7015         this.onLoad();
7016         
7017     }
7018     
7019 });
7020
7021  
7022
7023  /*
7024  * - LGPL
7025  *
7026  * table cell
7027  * 
7028  */
7029
7030 /**
7031  * @class Roo.bootstrap.TableCell
7032  * @extends Roo.bootstrap.Component
7033  * Bootstrap TableCell class
7034  * @cfg {String} html cell contain text
7035  * @cfg {String} cls cell class
7036  * @cfg {String} tag cell tag (td|th) default td
7037  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7038  * @cfg {String} align Aligns the content in a cell
7039  * @cfg {String} axis Categorizes cells
7040  * @cfg {String} bgcolor Specifies the background color of a cell
7041  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7042  * @cfg {Number} colspan Specifies the number of columns a cell should span
7043  * @cfg {String} headers Specifies one or more header cells a cell is related to
7044  * @cfg {Number} height Sets the height of a cell
7045  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7046  * @cfg {Number} rowspan Sets the number of rows a cell should span
7047  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7048  * @cfg {String} valign Vertical aligns the content in a cell
7049  * @cfg {Number} width Specifies the width of a cell
7050  * 
7051  * @constructor
7052  * Create a new TableCell
7053  * @param {Object} config The config object
7054  */
7055
7056 Roo.bootstrap.TableCell = function(config){
7057     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7058 };
7059
7060 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
7061     
7062     html: false,
7063     cls: false,
7064     tag: false,
7065     abbr: false,
7066     align: false,
7067     axis: false,
7068     bgcolor: false,
7069     charoff: false,
7070     colspan: false,
7071     headers: false,
7072     height: false,
7073     nowrap: false,
7074     rowspan: false,
7075     scope: false,
7076     valign: false,
7077     width: false,
7078     
7079     
7080     getAutoCreate : function(){
7081         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7082         
7083         cfg = {
7084             tag: 'td'
7085         };
7086         
7087         if(this.tag){
7088             cfg.tag = this.tag;
7089         }
7090         
7091         if (this.html) {
7092             cfg.html=this.html
7093         }
7094         if (this.cls) {
7095             cfg.cls=this.cls
7096         }
7097         if (this.abbr) {
7098             cfg.abbr=this.abbr
7099         }
7100         if (this.align) {
7101             cfg.align=this.align
7102         }
7103         if (this.axis) {
7104             cfg.axis=this.axis
7105         }
7106         if (this.bgcolor) {
7107             cfg.bgcolor=this.bgcolor
7108         }
7109         if (this.charoff) {
7110             cfg.charoff=this.charoff
7111         }
7112         if (this.colspan) {
7113             cfg.colspan=this.colspan
7114         }
7115         if (this.headers) {
7116             cfg.headers=this.headers
7117         }
7118         if (this.height) {
7119             cfg.height=this.height
7120         }
7121         if (this.nowrap) {
7122             cfg.nowrap=this.nowrap
7123         }
7124         if (this.rowspan) {
7125             cfg.rowspan=this.rowspan
7126         }
7127         if (this.scope) {
7128             cfg.scope=this.scope
7129         }
7130         if (this.valign) {
7131             cfg.valign=this.valign
7132         }
7133         if (this.width) {
7134             cfg.width=this.width
7135         }
7136         
7137         
7138         return cfg;
7139     }
7140    
7141 });
7142
7143  
7144
7145  /*
7146  * - LGPL
7147  *
7148  * table row
7149  * 
7150  */
7151
7152 /**
7153  * @class Roo.bootstrap.TableRow
7154  * @extends Roo.bootstrap.Component
7155  * Bootstrap TableRow class
7156  * @cfg {String} cls row class
7157  * @cfg {String} align Aligns the content in a table row
7158  * @cfg {String} bgcolor Specifies a background color for a table row
7159  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7160  * @cfg {String} valign Vertical aligns the content in a table row
7161  * 
7162  * @constructor
7163  * Create a new TableRow
7164  * @param {Object} config The config object
7165  */
7166
7167 Roo.bootstrap.TableRow = function(config){
7168     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7169 };
7170
7171 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
7172     
7173     cls: false,
7174     align: false,
7175     bgcolor: false,
7176     charoff: false,
7177     valign: false,
7178     
7179     getAutoCreate : function(){
7180         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7181         
7182         cfg = {
7183             tag: 'tr'
7184         };
7185             
7186         if(this.cls){
7187             cfg.cls = this.cls;
7188         }
7189         if(this.align){
7190             cfg.align = this.align;
7191         }
7192         if(this.bgcolor){
7193             cfg.bgcolor = this.bgcolor;
7194         }
7195         if(this.charoff){
7196             cfg.charoff = this.charoff;
7197         }
7198         if(this.valign){
7199             cfg.valign = this.valign;
7200         }
7201         
7202         return cfg;
7203     }
7204    
7205 });
7206
7207  
7208
7209  /*
7210  * - LGPL
7211  *
7212  * table body
7213  * 
7214  */
7215
7216 /**
7217  * @class Roo.bootstrap.TableBody
7218  * @extends Roo.bootstrap.Component
7219  * Bootstrap TableBody class
7220  * @cfg {String} cls element class
7221  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7222  * @cfg {String} align Aligns the content inside the element
7223  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7224  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7225  * 
7226  * @constructor
7227  * Create a new TableBody
7228  * @param {Object} config The config object
7229  */
7230
7231 Roo.bootstrap.TableBody = function(config){
7232     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7233 };
7234
7235 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
7236     
7237     cls: false,
7238     tag: false,
7239     align: false,
7240     charoff: false,
7241     valign: false,
7242     
7243     getAutoCreate : function(){
7244         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7245         
7246         cfg = {
7247             tag: 'tbody'
7248         };
7249             
7250         if (this.cls) {
7251             cfg.cls=this.cls
7252         }
7253         if(this.tag){
7254             cfg.tag = this.tag;
7255         }
7256         
7257         if(this.align){
7258             cfg.align = this.align;
7259         }
7260         if(this.charoff){
7261             cfg.charoff = this.charoff;
7262         }
7263         if(this.valign){
7264             cfg.valign = this.valign;
7265         }
7266         
7267         return cfg;
7268     }
7269     
7270     
7271 //    initEvents : function()
7272 //    {
7273 //        
7274 //        if(!this.store){
7275 //            return;
7276 //        }
7277 //        
7278 //        this.store = Roo.factory(this.store, Roo.data);
7279 //        this.store.on('load', this.onLoad, this);
7280 //        
7281 //        this.store.load();
7282 //        
7283 //    },
7284 //    
7285 //    onLoad: function () 
7286 //    {   
7287 //        this.fireEvent('load', this);
7288 //    }
7289 //    
7290 //   
7291 });
7292
7293  
7294
7295  /*
7296  * Based on:
7297  * Ext JS Library 1.1.1
7298  * Copyright(c) 2006-2007, Ext JS, LLC.
7299  *
7300  * Originally Released Under LGPL - original licence link has changed is not relivant.
7301  *
7302  * Fork - LGPL
7303  * <script type="text/javascript">
7304  */
7305
7306 // as we use this in bootstrap.
7307 Roo.namespace('Roo.form');
7308  /**
7309  * @class Roo.form.Action
7310  * Internal Class used to handle form actions
7311  * @constructor
7312  * @param {Roo.form.BasicForm} el The form element or its id
7313  * @param {Object} config Configuration options
7314  */
7315
7316  
7317  
7318 // define the action interface
7319 Roo.form.Action = function(form, options){
7320     this.form = form;
7321     this.options = options || {};
7322 };
7323 /**
7324  * Client Validation Failed
7325  * @const 
7326  */
7327 Roo.form.Action.CLIENT_INVALID = 'client';
7328 /**
7329  * Server Validation Failed
7330  * @const 
7331  */
7332 Roo.form.Action.SERVER_INVALID = 'server';
7333  /**
7334  * Connect to Server Failed
7335  * @const 
7336  */
7337 Roo.form.Action.CONNECT_FAILURE = 'connect';
7338 /**
7339  * Reading Data from Server Failed
7340  * @const 
7341  */
7342 Roo.form.Action.LOAD_FAILURE = 'load';
7343
7344 Roo.form.Action.prototype = {
7345     type : 'default',
7346     failureType : undefined,
7347     response : undefined,
7348     result : undefined,
7349
7350     // interface method
7351     run : function(options){
7352
7353     },
7354
7355     // interface method
7356     success : function(response){
7357
7358     },
7359
7360     // interface method
7361     handleResponse : function(response){
7362
7363     },
7364
7365     // default connection failure
7366     failure : function(response){
7367         
7368         this.response = response;
7369         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7370         this.form.afterAction(this, false);
7371     },
7372
7373     processResponse : function(response){
7374         this.response = response;
7375         if(!response.responseText){
7376             return true;
7377         }
7378         this.result = this.handleResponse(response);
7379         return this.result;
7380     },
7381
7382     // utility functions used internally
7383     getUrl : function(appendParams){
7384         var url = this.options.url || this.form.url || this.form.el.dom.action;
7385         if(appendParams){
7386             var p = this.getParams();
7387             if(p){
7388                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7389             }
7390         }
7391         return url;
7392     },
7393
7394     getMethod : function(){
7395         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7396     },
7397
7398     getParams : function(){
7399         var bp = this.form.baseParams;
7400         var p = this.options.params;
7401         if(p){
7402             if(typeof p == "object"){
7403                 p = Roo.urlEncode(Roo.applyIf(p, bp));
7404             }else if(typeof p == 'string' && bp){
7405                 p += '&' + Roo.urlEncode(bp);
7406             }
7407         }else if(bp){
7408             p = Roo.urlEncode(bp);
7409         }
7410         return p;
7411     },
7412
7413     createCallback : function(){
7414         return {
7415             success: this.success,
7416             failure: this.failure,
7417             scope: this,
7418             timeout: (this.form.timeout*1000),
7419             upload: this.form.fileUpload ? this.success : undefined
7420         };
7421     }
7422 };
7423
7424 Roo.form.Action.Submit = function(form, options){
7425     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7426 };
7427
7428 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7429     type : 'submit',
7430
7431     haveProgress : false,
7432     uploadComplete : false,
7433     
7434     // uploadProgress indicator.
7435     uploadProgress : function()
7436     {
7437         if (!this.form.progressUrl) {
7438             return;
7439         }
7440         
7441         if (!this.haveProgress) {
7442             Roo.MessageBox.progress("Uploading", "Uploading");
7443         }
7444         if (this.uploadComplete) {
7445            Roo.MessageBox.hide();
7446            return;
7447         }
7448         
7449         this.haveProgress = true;
7450    
7451         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7452         
7453         var c = new Roo.data.Connection();
7454         c.request({
7455             url : this.form.progressUrl,
7456             params: {
7457                 id : uid
7458             },
7459             method: 'GET',
7460             success : function(req){
7461                //console.log(data);
7462                 var rdata = false;
7463                 var edata;
7464                 try  {
7465                    rdata = Roo.decode(req.responseText)
7466                 } catch (e) {
7467                     Roo.log("Invalid data from server..");
7468                     Roo.log(edata);
7469                     return;
7470                 }
7471                 if (!rdata || !rdata.success) {
7472                     Roo.log(rdata);
7473                     Roo.MessageBox.alert(Roo.encode(rdata));
7474                     return;
7475                 }
7476                 var data = rdata.data;
7477                 
7478                 if (this.uploadComplete) {
7479                    Roo.MessageBox.hide();
7480                    return;
7481                 }
7482                    
7483                 if (data){
7484                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7485                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7486                     );
7487                 }
7488                 this.uploadProgress.defer(2000,this);
7489             },
7490        
7491             failure: function(data) {
7492                 Roo.log('progress url failed ');
7493                 Roo.log(data);
7494             },
7495             scope : this
7496         });
7497            
7498     },
7499     
7500     
7501     run : function()
7502     {
7503         // run get Values on the form, so it syncs any secondary forms.
7504         this.form.getValues();
7505         
7506         var o = this.options;
7507         var method = this.getMethod();
7508         var isPost = method == 'POST';
7509         if(o.clientValidation === false || this.form.isValid()){
7510             
7511             if (this.form.progressUrl) {
7512                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7513                     (new Date() * 1) + '' + Math.random());
7514                     
7515             } 
7516             
7517             
7518             Roo.Ajax.request(Roo.apply(this.createCallback(), {
7519                 form:this.form.el.dom,
7520                 url:this.getUrl(!isPost),
7521                 method: method,
7522                 params:isPost ? this.getParams() : null,
7523                 isUpload: this.form.fileUpload
7524             }));
7525             
7526             this.uploadProgress();
7527
7528         }else if (o.clientValidation !== false){ // client validation failed
7529             this.failureType = Roo.form.Action.CLIENT_INVALID;
7530             this.form.afterAction(this, false);
7531         }
7532     },
7533
7534     success : function(response)
7535     {
7536         this.uploadComplete= true;
7537         if (this.haveProgress) {
7538             Roo.MessageBox.hide();
7539         }
7540         
7541         
7542         var result = this.processResponse(response);
7543         if(result === true || result.success){
7544             this.form.afterAction(this, true);
7545             return;
7546         }
7547         if(result.errors){
7548             this.form.markInvalid(result.errors);
7549             this.failureType = Roo.form.Action.SERVER_INVALID;
7550         }
7551         this.form.afterAction(this, false);
7552     },
7553     failure : function(response)
7554     {
7555         this.uploadComplete= true;
7556         if (this.haveProgress) {
7557             Roo.MessageBox.hide();
7558         }
7559         
7560         this.response = response;
7561         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7562         this.form.afterAction(this, false);
7563     },
7564     
7565     handleResponse : function(response){
7566         if(this.form.errorReader){
7567             var rs = this.form.errorReader.read(response);
7568             var errors = [];
7569             if(rs.records){
7570                 for(var i = 0, len = rs.records.length; i < len; i++) {
7571                     var r = rs.records[i];
7572                     errors[i] = r.data;
7573                 }
7574             }
7575             if(errors.length < 1){
7576                 errors = null;
7577             }
7578             return {
7579                 success : rs.success,
7580                 errors : errors
7581             };
7582         }
7583         var ret = false;
7584         try {
7585             ret = Roo.decode(response.responseText);
7586         } catch (e) {
7587             ret = {
7588                 success: false,
7589                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7590                 errors : []
7591             };
7592         }
7593         return ret;
7594         
7595     }
7596 });
7597
7598
7599 Roo.form.Action.Load = function(form, options){
7600     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7601     this.reader = this.form.reader;
7602 };
7603
7604 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7605     type : 'load',
7606
7607     run : function(){
7608         
7609         Roo.Ajax.request(Roo.apply(
7610                 this.createCallback(), {
7611                     method:this.getMethod(),
7612                     url:this.getUrl(false),
7613                     params:this.getParams()
7614         }));
7615     },
7616
7617     success : function(response){
7618         
7619         var result = this.processResponse(response);
7620         if(result === true || !result.success || !result.data){
7621             this.failureType = Roo.form.Action.LOAD_FAILURE;
7622             this.form.afterAction(this, false);
7623             return;
7624         }
7625         this.form.clearInvalid();
7626         this.form.setValues(result.data);
7627         this.form.afterAction(this, true);
7628     },
7629
7630     handleResponse : function(response){
7631         if(this.form.reader){
7632             var rs = this.form.reader.read(response);
7633             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7634             return {
7635                 success : rs.success,
7636                 data : data
7637             };
7638         }
7639         return Roo.decode(response.responseText);
7640     }
7641 });
7642
7643 Roo.form.Action.ACTION_TYPES = {
7644     'load' : Roo.form.Action.Load,
7645     'submit' : Roo.form.Action.Submit
7646 };/*
7647  * - LGPL
7648  *
7649  * form
7650  *
7651  */
7652
7653 /**
7654  * @class Roo.bootstrap.Form
7655  * @extends Roo.bootstrap.Component
7656  * Bootstrap Form class
7657  * @cfg {String} method  GET | POST (default POST)
7658  * @cfg {String} labelAlign top | left (default top)
7659  * @cfg {String} align left  | right - for navbars
7660  * @cfg {Boolean} loadMask load mask when submit (default true)
7661
7662  *
7663  * @constructor
7664  * Create a new Form
7665  * @param {Object} config The config object
7666  */
7667
7668
7669 Roo.bootstrap.Form = function(config){
7670     
7671     Roo.bootstrap.Form.superclass.constructor.call(this, config);
7672     
7673     Roo.bootstrap.Form.popover.apply();
7674     
7675     this.addEvents({
7676         /**
7677          * @event clientvalidation
7678          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7679          * @param {Form} this
7680          * @param {Boolean} valid true if the form has passed client-side validation
7681          */
7682         clientvalidation: true,
7683         /**
7684          * @event beforeaction
7685          * Fires before any action is performed. Return false to cancel the action.
7686          * @param {Form} this
7687          * @param {Action} action The action to be performed
7688          */
7689         beforeaction: true,
7690         /**
7691          * @event actionfailed
7692          * Fires when an action fails.
7693          * @param {Form} this
7694          * @param {Action} action The action that failed
7695          */
7696         actionfailed : true,
7697         /**
7698          * @event actioncomplete
7699          * Fires when an action is completed.
7700          * @param {Form} this
7701          * @param {Action} action The action that completed
7702          */
7703         actioncomplete : true
7704     });
7705 };
7706
7707 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
7708
7709      /**
7710      * @cfg {String} method
7711      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7712      */
7713     method : 'POST',
7714     /**
7715      * @cfg {String} url
7716      * The URL to use for form actions if one isn't supplied in the action options.
7717      */
7718     /**
7719      * @cfg {Boolean} fileUpload
7720      * Set to true if this form is a file upload.
7721      */
7722
7723     /**
7724      * @cfg {Object} baseParams
7725      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7726      */
7727
7728     /**
7729      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7730      */
7731     timeout: 30,
7732     /**
7733      * @cfg {Sting} align (left|right) for navbar forms
7734      */
7735     align : 'left',
7736
7737     // private
7738     activeAction : null,
7739
7740     /**
7741      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7742      * element by passing it or its id or mask the form itself by passing in true.
7743      * @type Mixed
7744      */
7745     waitMsgTarget : false,
7746
7747     loadMask : true,
7748     
7749     /**
7750      * @cfg {Boolean} errorMask (true|false) default false
7751      */
7752     errorMask : false,
7753     
7754     /**
7755      * @cfg {Number} maskOffset Default 100
7756      */
7757     maskOffset : 100,
7758     
7759     /**
7760      * @cfg {Boolean} maskBody
7761      */
7762     maskBody : false,
7763
7764     getAutoCreate : function(){
7765
7766         var cfg = {
7767             tag: 'form',
7768             method : this.method || 'POST',
7769             id : this.id || Roo.id(),
7770             cls : ''
7771         };
7772         if (this.parent().xtype.match(/^Nav/)) {
7773             cfg.cls = 'navbar-form navbar-' + this.align;
7774
7775         }
7776
7777         if (this.labelAlign == 'left' ) {
7778             cfg.cls += ' form-horizontal';
7779         }
7780
7781
7782         return cfg;
7783     },
7784     initEvents : function()
7785     {
7786         this.el.on('submit', this.onSubmit, this);
7787         // this was added as random key presses on the form where triggering form submit.
7788         this.el.on('keypress', function(e) {
7789             if (e.getCharCode() != 13) {
7790                 return true;
7791             }
7792             // we might need to allow it for textareas.. and some other items.
7793             // check e.getTarget().
7794
7795             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7796                 return true;
7797             }
7798
7799             Roo.log("keypress blocked");
7800
7801             e.preventDefault();
7802             return false;
7803         });
7804         
7805     },
7806     // private
7807     onSubmit : function(e){
7808         e.stopEvent();
7809     },
7810
7811      /**
7812      * Returns true if client-side validation on the form is successful.
7813      * @return Boolean
7814      */
7815     isValid : function(){
7816         var items = this.getItems();
7817         var valid = true;
7818         var target = false;
7819         
7820         items.each(function(f){
7821             
7822             if(f.validate()){
7823                 return;
7824             }
7825             
7826             valid = false;
7827
7828             if(!target && f.el.isVisible(true)){
7829                 target = f;
7830             }
7831            
7832         });
7833         
7834         if(this.errorMask && !valid){
7835             Roo.bootstrap.Form.popover.mask(this, target);
7836         }
7837         
7838         return valid;
7839     },
7840     
7841     /**
7842      * Returns true if any fields in this form have changed since their original load.
7843      * @return Boolean
7844      */
7845     isDirty : function(){
7846         var dirty = false;
7847         var items = this.getItems();
7848         items.each(function(f){
7849            if(f.isDirty()){
7850                dirty = true;
7851                return false;
7852            }
7853            return true;
7854         });
7855         return dirty;
7856     },
7857      /**
7858      * Performs a predefined action (submit or load) or custom actions you define on this form.
7859      * @param {String} actionName The name of the action type
7860      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
7861      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7862      * accept other config options):
7863      * <pre>
7864 Property          Type             Description
7865 ----------------  ---------------  ----------------------------------------------------------------------------------
7866 url               String           The url for the action (defaults to the form's url)
7867 method            String           The form method to use (defaults to the form's method, or POST if not defined)
7868 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
7869 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
7870                                    validate the form on the client (defaults to false)
7871      * </pre>
7872      * @return {BasicForm} this
7873      */
7874     doAction : function(action, options){
7875         if(typeof action == 'string'){
7876             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7877         }
7878         if(this.fireEvent('beforeaction', this, action) !== false){
7879             this.beforeAction(action);
7880             action.run.defer(100, action);
7881         }
7882         return this;
7883     },
7884
7885     // private
7886     beforeAction : function(action){
7887         var o = action.options;
7888         
7889         if(this.loadMask){
7890             
7891             if(this.maskBody){
7892                 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7893             } else {
7894                 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7895             }
7896         }
7897         // not really supported yet.. ??
7898
7899         //if(this.waitMsgTarget === true){
7900         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7901         //}else if(this.waitMsgTarget){
7902         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7903         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7904         //}else {
7905         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7906        // }
7907
7908     },
7909
7910     // private
7911     afterAction : function(action, success){
7912         this.activeAction = null;
7913         var o = action.options;
7914
7915         if(this.loadMask){
7916             
7917             if(this.maskBody){
7918                 Roo.get(document.body).unmask();
7919             } else {
7920                 this.el.unmask();
7921             }
7922         }
7923         
7924         //if(this.waitMsgTarget === true){
7925 //            this.el.unmask();
7926         //}else if(this.waitMsgTarget){
7927         //    this.waitMsgTarget.unmask();
7928         //}else{
7929         //    Roo.MessageBox.updateProgress(1);
7930         //    Roo.MessageBox.hide();
7931        // }
7932         //
7933         if(success){
7934             if(o.reset){
7935                 this.reset();
7936             }
7937             Roo.callback(o.success, o.scope, [this, action]);
7938             this.fireEvent('actioncomplete', this, action);
7939
7940         }else{
7941
7942             // failure condition..
7943             // we have a scenario where updates need confirming.
7944             // eg. if a locking scenario exists..
7945             // we look for { errors : { needs_confirm : true }} in the response.
7946             if (
7947                 (typeof(action.result) != 'undefined')  &&
7948                 (typeof(action.result.errors) != 'undefined')  &&
7949                 (typeof(action.result.errors.needs_confirm) != 'undefined')
7950            ){
7951                 var _t = this;
7952                 Roo.log("not supported yet");
7953                  /*
7954
7955                 Roo.MessageBox.confirm(
7956                     "Change requires confirmation",
7957                     action.result.errorMsg,
7958                     function(r) {
7959                         if (r != 'yes') {
7960                             return;
7961                         }
7962                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
7963                     }
7964
7965                 );
7966                 */
7967
7968
7969                 return;
7970             }
7971
7972             Roo.callback(o.failure, o.scope, [this, action]);
7973             // show an error message if no failed handler is set..
7974             if (!this.hasListener('actionfailed')) {
7975                 Roo.log("need to add dialog support");
7976                 /*
7977                 Roo.MessageBox.alert("Error",
7978                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7979                         action.result.errorMsg :
7980                         "Saving Failed, please check your entries or try again"
7981                 );
7982                 */
7983             }
7984
7985             this.fireEvent('actionfailed', this, action);
7986         }
7987
7988     },
7989     /**
7990      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7991      * @param {String} id The value to search for
7992      * @return Field
7993      */
7994     findField : function(id){
7995         var items = this.getItems();
7996         var field = items.get(id);
7997         if(!field){
7998              items.each(function(f){
7999                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8000                     field = f;
8001                     return false;
8002                 }
8003                 return true;
8004             });
8005         }
8006         return field || null;
8007     },
8008      /**
8009      * Mark fields in this form invalid in bulk.
8010      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8011      * @return {BasicForm} this
8012      */
8013     markInvalid : function(errors){
8014         if(errors instanceof Array){
8015             for(var i = 0, len = errors.length; i < len; i++){
8016                 var fieldError = errors[i];
8017                 var f = this.findField(fieldError.id);
8018                 if(f){
8019                     f.markInvalid(fieldError.msg);
8020                 }
8021             }
8022         }else{
8023             var field, id;
8024             for(id in errors){
8025                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8026                     field.markInvalid(errors[id]);
8027                 }
8028             }
8029         }
8030         //Roo.each(this.childForms || [], function (f) {
8031         //    f.markInvalid(errors);
8032         //});
8033
8034         return this;
8035     },
8036
8037     /**
8038      * Set values for fields in this form in bulk.
8039      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8040      * @return {BasicForm} this
8041      */
8042     setValues : function(values){
8043         if(values instanceof Array){ // array of objects
8044             for(var i = 0, len = values.length; i < len; i++){
8045                 var v = values[i];
8046                 var f = this.findField(v.id);
8047                 if(f){
8048                     f.setValue(v.value);
8049                     if(this.trackResetOnLoad){
8050                         f.originalValue = f.getValue();
8051                     }
8052                 }
8053             }
8054         }else{ // object hash
8055             var field, id;
8056             for(id in values){
8057                 if(typeof values[id] != 'function' && (field = this.findField(id))){
8058
8059                     if (field.setFromData &&
8060                         field.valueField &&
8061                         field.displayField &&
8062                         // combos' with local stores can
8063                         // be queried via setValue()
8064                         // to set their value..
8065                         (field.store && !field.store.isLocal)
8066                         ) {
8067                         // it's a combo
8068                         var sd = { };
8069                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8070                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8071                         field.setFromData(sd);
8072
8073                     } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8074                         
8075                         field.setFromData(values);
8076                         
8077                     } else {
8078                         field.setValue(values[id]);
8079                     }
8080
8081
8082                     if(this.trackResetOnLoad){
8083                         field.originalValue = field.getValue();
8084                     }
8085                 }
8086             }
8087         }
8088
8089         //Roo.each(this.childForms || [], function (f) {
8090         //    f.setValues(values);
8091         //});
8092
8093         return this;
8094     },
8095
8096     /**
8097      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8098      * they are returned as an array.
8099      * @param {Boolean} asString
8100      * @return {Object}
8101      */
8102     getValues : function(asString){
8103         //if (this.childForms) {
8104             // copy values from the child forms
8105         //    Roo.each(this.childForms, function (f) {
8106         //        this.setValues(f.getValues());
8107         //    }, this);
8108         //}
8109
8110
8111
8112         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8113         if(asString === true){
8114             return fs;
8115         }
8116         return Roo.urlDecode(fs);
8117     },
8118
8119     /**
8120      * Returns the fields in this form as an object with key/value pairs.
8121      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8122      * @return {Object}
8123      */
8124     getFieldValues : function(with_hidden)
8125     {
8126         var items = this.getItems();
8127         var ret = {};
8128         items.each(function(f){
8129             
8130             if (!f.getName()) {
8131                 return;
8132             }
8133             
8134             var v = f.getValue();
8135             
8136             if (f.inputType =='radio') {
8137                 if (typeof(ret[f.getName()]) == 'undefined') {
8138                     ret[f.getName()] = ''; // empty..
8139                 }
8140
8141                 if (!f.el.dom.checked) {
8142                     return;
8143
8144                 }
8145                 v = f.el.dom.value;
8146
8147             }
8148             
8149             if(f.xtype == 'MoneyField'){
8150                 ret[f.currencyName] = f.getCurrency();
8151             }
8152
8153             // not sure if this supported any more..
8154             if ((typeof(v) == 'object') && f.getRawValue) {
8155                 v = f.getRawValue() ; // dates..
8156             }
8157             // combo boxes where name != hiddenName...
8158             if (f.name !== false && f.name != '' && f.name != f.getName()) {
8159                 ret[f.name] = f.getRawValue();
8160             }
8161             ret[f.getName()] = v;
8162         });
8163
8164         return ret;
8165     },
8166
8167     /**
8168      * Clears all invalid messages in this form.
8169      * @return {BasicForm} this
8170      */
8171     clearInvalid : function(){
8172         var items = this.getItems();
8173
8174         items.each(function(f){
8175            f.clearInvalid();
8176         });
8177
8178         return this;
8179     },
8180
8181     /**
8182      * Resets this form.
8183      * @return {BasicForm} this
8184      */
8185     reset : function(){
8186         var items = this.getItems();
8187         items.each(function(f){
8188             f.reset();
8189         });
8190
8191         Roo.each(this.childForms || [], function (f) {
8192             f.reset();
8193         });
8194
8195
8196         return this;
8197     },
8198     
8199     getItems : function()
8200     {
8201         var r=new Roo.util.MixedCollection(false, function(o){
8202             return o.id || (o.id = Roo.id());
8203         });
8204         var iter = function(el) {
8205             if (el.inputEl) {
8206                 r.add(el);
8207             }
8208             if (!el.items) {
8209                 return;
8210             }
8211             Roo.each(el.items,function(e) {
8212                 iter(e);
8213             });
8214         };
8215
8216         iter(this);
8217         return r;
8218     },
8219     
8220     hideFields : function(items)
8221     {
8222         Roo.each(items, function(i){
8223             
8224             var f = this.findField(i);
8225             
8226             if(!f){
8227                 return;
8228             }
8229             
8230             if(f.xtype == 'DateField'){
8231                 f.setVisible(false);
8232                 return;
8233             }
8234             
8235             f.hide();
8236             
8237         }, this);
8238     },
8239     
8240     showFields : function(items)
8241     {
8242         Roo.each(items, function(i){
8243             
8244             var f = this.findField(i);
8245             
8246             if(!f){
8247                 return;
8248             }
8249             
8250             if(f.xtype == 'DateField'){
8251                 f.setVisible(true);
8252                 return;
8253             }
8254             
8255             f.show();
8256             
8257         }, this);
8258     }
8259
8260 });
8261
8262 Roo.apply(Roo.bootstrap.Form, {
8263     
8264     popover : {
8265         
8266         padding : 5,
8267         
8268         isApplied : false,
8269         
8270         isMasked : false,
8271         
8272         form : false,
8273         
8274         target : false,
8275         
8276         toolTip : false,
8277         
8278         intervalID : false,
8279         
8280         maskEl : false,
8281         
8282         apply : function()
8283         {
8284             if(this.isApplied){
8285                 return;
8286             }
8287             
8288             this.maskEl = {
8289                 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8290                 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8291                 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8292                 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8293             };
8294             
8295             this.maskEl.top.enableDisplayMode("block");
8296             this.maskEl.left.enableDisplayMode("block");
8297             this.maskEl.bottom.enableDisplayMode("block");
8298             this.maskEl.right.enableDisplayMode("block");
8299             
8300             this.toolTip = new Roo.bootstrap.Tooltip({
8301                 cls : 'roo-form-error-popover',
8302                 alignment : {
8303                     'left' : ['r-l', [-2,0], 'right'],
8304                     'right' : ['l-r', [2,0], 'left'],
8305                     'bottom' : ['tl-bl', [0,2], 'top'],
8306                     'top' : [ 'bl-tl', [0,-2], 'bottom']
8307                 }
8308             });
8309             
8310             this.toolTip.render(Roo.get(document.body));
8311
8312             this.toolTip.el.enableDisplayMode("block");
8313             
8314             Roo.get(document.body).on('click', function(){
8315                 this.unmask();
8316             }, this);
8317             
8318             Roo.get(document.body).on('touchstart', function(){
8319                 this.unmask();
8320             }, this);
8321             
8322             this.isApplied = true
8323         },
8324         
8325         mask : function(form, target)
8326         {
8327             this.form = form;
8328             
8329             this.target = target;
8330             
8331             if(!this.form.errorMask || !target.el){
8332                 return;
8333             }
8334             
8335             var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8336             
8337             Roo.log(scrollable);
8338             
8339             var ot = this.target.el.calcOffsetsTo(scrollable);
8340             
8341             var scrollTo = ot[1] - this.form.maskOffset;
8342             
8343             scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8344             
8345             scrollable.scrollTo('top', scrollTo);
8346             
8347             var box = this.target.el.getBox();
8348             Roo.log(box);
8349             var zIndex = Roo.bootstrap.Modal.zIndex++;
8350
8351             
8352             this.maskEl.top.setStyle('position', 'absolute');
8353             this.maskEl.top.setStyle('z-index', zIndex);
8354             this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8355             this.maskEl.top.setLeft(0);
8356             this.maskEl.top.setTop(0);
8357             this.maskEl.top.show();
8358             
8359             this.maskEl.left.setStyle('position', 'absolute');
8360             this.maskEl.left.setStyle('z-index', zIndex);
8361             this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8362             this.maskEl.left.setLeft(0);
8363             this.maskEl.left.setTop(box.y - this.padding);
8364             this.maskEl.left.show();
8365
8366             this.maskEl.bottom.setStyle('position', 'absolute');
8367             this.maskEl.bottom.setStyle('z-index', zIndex);
8368             this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8369             this.maskEl.bottom.setLeft(0);
8370             this.maskEl.bottom.setTop(box.bottom + this.padding);
8371             this.maskEl.bottom.show();
8372
8373             this.maskEl.right.setStyle('position', 'absolute');
8374             this.maskEl.right.setStyle('z-index', zIndex);
8375             this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8376             this.maskEl.right.setLeft(box.right + this.padding);
8377             this.maskEl.right.setTop(box.y - this.padding);
8378             this.maskEl.right.show();
8379
8380             this.toolTip.bindEl = this.target.el;
8381
8382             this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8383
8384             var tip = this.target.blankText;
8385
8386             if(this.target.getValue() !== '' ) {
8387                 
8388                 if (this.target.invalidText.length) {
8389                     tip = this.target.invalidText;
8390                 } else if (this.target.regexText.length){
8391                     tip = this.target.regexText;
8392                 }
8393             }
8394
8395             this.toolTip.show(tip);
8396
8397             this.intervalID = window.setInterval(function() {
8398                 Roo.bootstrap.Form.popover.unmask();
8399             }, 10000);
8400
8401             window.onwheel = function(){ return false;};
8402             
8403             (function(){ this.isMasked = true; }).defer(500, this);
8404             
8405         },
8406         
8407         unmask : function()
8408         {
8409             if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8410                 return;
8411             }
8412             
8413             this.maskEl.top.setStyle('position', 'absolute');
8414             this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8415             this.maskEl.top.hide();
8416
8417             this.maskEl.left.setStyle('position', 'absolute');
8418             this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8419             this.maskEl.left.hide();
8420
8421             this.maskEl.bottom.setStyle('position', 'absolute');
8422             this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8423             this.maskEl.bottom.hide();
8424
8425             this.maskEl.right.setStyle('position', 'absolute');
8426             this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8427             this.maskEl.right.hide();
8428             
8429             this.toolTip.hide();
8430             
8431             this.toolTip.el.hide();
8432             
8433             window.onwheel = function(){ return true;};
8434             
8435             if(this.intervalID){
8436                 window.clearInterval(this.intervalID);
8437                 this.intervalID = false;
8438             }
8439             
8440             this.isMasked = false;
8441             
8442         }
8443         
8444     }
8445     
8446 });
8447
8448 /*
8449  * Based on:
8450  * Ext JS Library 1.1.1
8451  * Copyright(c) 2006-2007, Ext JS, LLC.
8452  *
8453  * Originally Released Under LGPL - original licence link has changed is not relivant.
8454  *
8455  * Fork - LGPL
8456  * <script type="text/javascript">
8457  */
8458 /**
8459  * @class Roo.form.VTypes
8460  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8461  * @singleton
8462  */
8463 Roo.form.VTypes = function(){
8464     // closure these in so they are only created once.
8465     var alpha = /^[a-zA-Z_]+$/;
8466     var alphanum = /^[a-zA-Z0-9_]+$/;
8467     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8468     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8469
8470     // All these messages and functions are configurable
8471     return {
8472         /**
8473          * The function used to validate email addresses
8474          * @param {String} value The email address
8475          */
8476         'email' : function(v){
8477             return email.test(v);
8478         },
8479         /**
8480          * The error text to display when the email validation function returns false
8481          * @type String
8482          */
8483         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8484         /**
8485          * The keystroke filter mask to be applied on email input
8486          * @type RegExp
8487          */
8488         'emailMask' : /[a-z0-9_\.\-@]/i,
8489
8490         /**
8491          * The function used to validate URLs
8492          * @param {String} value The URL
8493          */
8494         'url' : function(v){
8495             return url.test(v);
8496         },
8497         /**
8498          * The error text to display when the url validation function returns false
8499          * @type String
8500          */
8501         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8502         
8503         /**
8504          * The function used to validate alpha values
8505          * @param {String} value The value
8506          */
8507         'alpha' : function(v){
8508             return alpha.test(v);
8509         },
8510         /**
8511          * The error text to display when the alpha validation function returns false
8512          * @type String
8513          */
8514         'alphaText' : 'This field should only contain letters and _',
8515         /**
8516          * The keystroke filter mask to be applied on alpha input
8517          * @type RegExp
8518          */
8519         'alphaMask' : /[a-z_]/i,
8520
8521         /**
8522          * The function used to validate alphanumeric values
8523          * @param {String} value The value
8524          */
8525         'alphanum' : function(v){
8526             return alphanum.test(v);
8527         },
8528         /**
8529          * The error text to display when the alphanumeric validation function returns false
8530          * @type String
8531          */
8532         'alphanumText' : 'This field should only contain letters, numbers and _',
8533         /**
8534          * The keystroke filter mask to be applied on alphanumeric input
8535          * @type RegExp
8536          */
8537         'alphanumMask' : /[a-z0-9_]/i
8538     };
8539 }();/*
8540  * - LGPL
8541  *
8542  * Input
8543  * 
8544  */
8545
8546 /**
8547  * @class Roo.bootstrap.Input
8548  * @extends Roo.bootstrap.Component
8549  * Bootstrap Input class
8550  * @cfg {Boolean} disabled is it disabled
8551  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8552  * @cfg {String} name name of the input
8553  * @cfg {string} fieldLabel - the label associated
8554  * @cfg {string} placeholder - placeholder to put in text.
8555  * @cfg {string}  before - input group add on before
8556  * @cfg {string} after - input group add on after
8557  * @cfg {string} size - (lg|sm) or leave empty..
8558  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8559  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8560  * @cfg {Number} md colspan out of 12 for computer-sized screens
8561  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8562  * @cfg {string} value default value of the input
8563  * @cfg {Number} labelWidth set the width of label 
8564  * @cfg {Number} labellg set the width of label (1-12)
8565  * @cfg {Number} labelmd set the width of label (1-12)
8566  * @cfg {Number} labelsm set the width of label (1-12)
8567  * @cfg {Number} labelxs set the width of label (1-12)
8568  * @cfg {String} labelAlign (top|left)
8569  * @cfg {Boolean} readOnly Specifies that the field should be read-only
8570  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8571  * @cfg {String} indicatorpos (left|right) default left
8572  * @cfg {String} capture (user|camera) use for file input only. (default empty)
8573  * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8574
8575  * @cfg {String} align (left|center|right) Default left
8576  * @cfg {Boolean} forceFeedback (true|false) Default false
8577  * 
8578  * @constructor
8579  * Create a new Input
8580  * @param {Object} config The config object
8581  */
8582
8583 Roo.bootstrap.Input = function(config){
8584     
8585     Roo.bootstrap.Input.superclass.constructor.call(this, config);
8586     
8587     this.addEvents({
8588         /**
8589          * @event focus
8590          * Fires when this field receives input focus.
8591          * @param {Roo.form.Field} this
8592          */
8593         focus : true,
8594         /**
8595          * @event blur
8596          * Fires when this field loses input focus.
8597          * @param {Roo.form.Field} this
8598          */
8599         blur : true,
8600         /**
8601          * @event specialkey
8602          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
8603          * {@link Roo.EventObject#getKey} to determine which key was pressed.
8604          * @param {Roo.form.Field} this
8605          * @param {Roo.EventObject} e The event object
8606          */
8607         specialkey : true,
8608         /**
8609          * @event change
8610          * Fires just before the field blurs if the field value has changed.
8611          * @param {Roo.form.Field} this
8612          * @param {Mixed} newValue The new value
8613          * @param {Mixed} oldValue The original value
8614          */
8615         change : true,
8616         /**
8617          * @event invalid
8618          * Fires after the field has been marked as invalid.
8619          * @param {Roo.form.Field} this
8620          * @param {String} msg The validation message
8621          */
8622         invalid : true,
8623         /**
8624          * @event valid
8625          * Fires after the field has been validated with no errors.
8626          * @param {Roo.form.Field} this
8627          */
8628         valid : true,
8629          /**
8630          * @event keyup
8631          * Fires after the key up
8632          * @param {Roo.form.Field} this
8633          * @param {Roo.EventObject}  e The event Object
8634          */
8635         keyup : true
8636     });
8637 };
8638
8639 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
8640      /**
8641      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8642       automatic validation (defaults to "keyup").
8643      */
8644     validationEvent : "keyup",
8645      /**
8646      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8647      */
8648     validateOnBlur : true,
8649     /**
8650      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8651      */
8652     validationDelay : 250,
8653      /**
8654      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8655      */
8656     focusClass : "x-form-focus",  // not needed???
8657     
8658        
8659     /**
8660      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8661      */
8662     invalidClass : "has-warning",
8663     
8664     /**
8665      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8666      */
8667     validClass : "has-success",
8668     
8669     /**
8670      * @cfg {Boolean} hasFeedback (true|false) default true
8671      */
8672     hasFeedback : true,
8673     
8674     /**
8675      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8676      */
8677     invalidFeedbackClass : "glyphicon-warning-sign",
8678     
8679     /**
8680      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8681      */
8682     validFeedbackClass : "glyphicon-ok",
8683     
8684     /**
8685      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8686      */
8687     selectOnFocus : false,
8688     
8689      /**
8690      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8691      */
8692     maskRe : null,
8693        /**
8694      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8695      */
8696     vtype : null,
8697     
8698       /**
8699      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8700      */
8701     disableKeyFilter : false,
8702     
8703        /**
8704      * @cfg {Boolean} disabled True to disable the field (defaults to false).
8705      */
8706     disabled : false,
8707      /**
8708      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8709      */
8710     allowBlank : true,
8711     /**
8712      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8713      */
8714     blankText : "Please complete this mandatory field",
8715     
8716      /**
8717      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8718      */
8719     minLength : 0,
8720     /**
8721      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8722      */
8723     maxLength : Number.MAX_VALUE,
8724     /**
8725      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8726      */
8727     minLengthText : "The minimum length for this field is {0}",
8728     /**
8729      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8730      */
8731     maxLengthText : "The maximum length for this field is {0}",
8732   
8733     
8734     /**
8735      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8736      * If available, this function will be called only after the basic validators all return true, and will be passed the
8737      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8738      */
8739     validator : null,
8740     /**
8741      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8742      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8743      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
8744      */
8745     regex : null,
8746     /**
8747      * @cfg {String} regexText -- Depricated - use Invalid Text
8748      */
8749     regexText : "",
8750     
8751     /**
8752      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8753      */
8754     invalidText : "",
8755     
8756     
8757     
8758     autocomplete: false,
8759     
8760     
8761     fieldLabel : '',
8762     inputType : 'text',
8763     
8764     name : false,
8765     placeholder: false,
8766     before : false,
8767     after : false,
8768     size : false,
8769     hasFocus : false,
8770     preventMark: false,
8771     isFormField : true,
8772     value : '',
8773     labelWidth : 2,
8774     labelAlign : false,
8775     readOnly : false,
8776     align : false,
8777     formatedValue : false,
8778     forceFeedback : false,
8779     
8780     indicatorpos : 'left',
8781     
8782     labellg : 0,
8783     labelmd : 0,
8784     labelsm : 0,
8785     labelxs : 0,
8786     
8787     capture : '',
8788     accept : '',
8789     
8790     parentLabelAlign : function()
8791     {
8792         var parent = this;
8793         while (parent.parent()) {
8794             parent = parent.parent();
8795             if (typeof(parent.labelAlign) !='undefined') {
8796                 return parent.labelAlign;
8797             }
8798         }
8799         return 'left';
8800         
8801     },
8802     
8803     getAutoCreate : function()
8804     {
8805         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8806         
8807         var id = Roo.id();
8808         
8809         var cfg = {};
8810         
8811         if(this.inputType != 'hidden'){
8812             cfg.cls = 'form-group' //input-group
8813         }
8814         
8815         var input =  {
8816             tag: 'input',
8817             id : id,
8818             type : this.inputType,
8819             value : this.value,
8820             cls : 'form-control',
8821             placeholder : this.placeholder || '',
8822             autocomplete : this.autocomplete || 'new-password'
8823         };
8824         
8825         if(this.capture.length){
8826             input.capture = this.capture;
8827         }
8828         
8829         if(this.accept.length){
8830             input.accept = this.accept + "/*";
8831         }
8832         
8833         if(this.align){
8834             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8835         }
8836         
8837         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8838             input.maxLength = this.maxLength;
8839         }
8840         
8841         if (this.disabled) {
8842             input.disabled=true;
8843         }
8844         
8845         if (this.readOnly) {
8846             input.readonly=true;
8847         }
8848         
8849         if (this.name) {
8850             input.name = this.name;
8851         }
8852         
8853         if (this.size) {
8854             input.cls += ' input-' + this.size;
8855         }
8856         
8857         var settings=this;
8858         ['xs','sm','md','lg'].map(function(size){
8859             if (settings[size]) {
8860                 cfg.cls += ' col-' + size + '-' + settings[size];
8861             }
8862         });
8863         
8864         var inputblock = input;
8865         
8866         var feedback = {
8867             tag: 'span',
8868             cls: 'glyphicon form-control-feedback'
8869         };
8870             
8871         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8872             
8873             inputblock = {
8874                 cls : 'has-feedback',
8875                 cn :  [
8876                     input,
8877                     feedback
8878                 ] 
8879             };  
8880         }
8881         
8882         if (this.before || this.after) {
8883             
8884             inputblock = {
8885                 cls : 'input-group',
8886                 cn :  [] 
8887             };
8888             
8889             if (this.before && typeof(this.before) == 'string') {
8890                 
8891                 inputblock.cn.push({
8892                     tag :'span',
8893                     cls : 'roo-input-before input-group-addon',
8894                     html : this.before
8895                 });
8896             }
8897             if (this.before && typeof(this.before) == 'object') {
8898                 this.before = Roo.factory(this.before);
8899                 
8900                 inputblock.cn.push({
8901                     tag :'span',
8902                     cls : 'roo-input-before input-group-' +
8903                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8904                 });
8905             }
8906             
8907             inputblock.cn.push(input);
8908             
8909             if (this.after && typeof(this.after) == 'string') {
8910                 inputblock.cn.push({
8911                     tag :'span',
8912                     cls : 'roo-input-after input-group-addon',
8913                     html : this.after
8914                 });
8915             }
8916             if (this.after && typeof(this.after) == 'object') {
8917                 this.after = Roo.factory(this.after);
8918                 
8919                 inputblock.cn.push({
8920                     tag :'span',
8921                     cls : 'roo-input-after input-group-' +
8922                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8923                 });
8924             }
8925             
8926             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8927                 inputblock.cls += ' has-feedback';
8928                 inputblock.cn.push(feedback);
8929             }
8930         };
8931         
8932         if (align ==='left' && this.fieldLabel.length) {
8933             
8934             cfg.cls += ' roo-form-group-label-left';
8935             
8936             cfg.cn = [
8937                 {
8938                     tag : 'i',
8939                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8940                     tooltip : 'This field is required'
8941                 },
8942                 {
8943                     tag: 'label',
8944                     'for' :  id,
8945                     cls : 'control-label',
8946                     html : this.fieldLabel
8947
8948                 },
8949                 {
8950                     cls : "", 
8951                     cn: [
8952                         inputblock
8953                     ]
8954                 }
8955             ];
8956             
8957             var labelCfg = cfg.cn[1];
8958             var contentCfg = cfg.cn[2];
8959             
8960             if(this.indicatorpos == 'right'){
8961                 cfg.cn = [
8962                     {
8963                         tag: 'label',
8964                         'for' :  id,
8965                         cls : 'control-label',
8966                         cn : [
8967                             {
8968                                 tag : 'span',
8969                                 html : this.fieldLabel
8970                             },
8971                             {
8972                                 tag : 'i',
8973                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8974                                 tooltip : 'This field is required'
8975                             }
8976                         ]
8977                     },
8978                     {
8979                         cls : "",
8980                         cn: [
8981                             inputblock
8982                         ]
8983                     }
8984
8985                 ];
8986                 
8987                 labelCfg = cfg.cn[0];
8988                 contentCfg = cfg.cn[1];
8989             
8990             }
8991             
8992             if(this.labelWidth > 12){
8993                 labelCfg.style = "width: " + this.labelWidth + 'px';
8994             }
8995             
8996             if(this.labelWidth < 13 && this.labelmd == 0){
8997                 this.labelmd = this.labelWidth;
8998             }
8999             
9000             if(this.labellg > 0){
9001                 labelCfg.cls += ' col-lg-' + this.labellg;
9002                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9003             }
9004             
9005             if(this.labelmd > 0){
9006                 labelCfg.cls += ' col-md-' + this.labelmd;
9007                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9008             }
9009             
9010             if(this.labelsm > 0){
9011                 labelCfg.cls += ' col-sm-' + this.labelsm;
9012                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9013             }
9014             
9015             if(this.labelxs > 0){
9016                 labelCfg.cls += ' col-xs-' + this.labelxs;
9017                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9018             }
9019             
9020             
9021         } else if ( this.fieldLabel.length) {
9022                 
9023             cfg.cn = [
9024                 {
9025                     tag : 'i',
9026                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9027                     tooltip : 'This field is required'
9028                 },
9029                 {
9030                     tag: 'label',
9031                    //cls : 'input-group-addon',
9032                     html : this.fieldLabel
9033
9034                 },
9035
9036                inputblock
9037
9038            ];
9039            
9040            if(this.indicatorpos == 'right'){
9041                 
9042                 cfg.cn = [
9043                     {
9044                         tag: 'label',
9045                        //cls : 'input-group-addon',
9046                         html : this.fieldLabel
9047
9048                     },
9049                     {
9050                         tag : 'i',
9051                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9052                         tooltip : 'This field is required'
9053                     },
9054
9055                    inputblock
9056
9057                ];
9058
9059             }
9060
9061         } else {
9062             
9063             cfg.cn = [
9064
9065                     inputblock
9066
9067             ];
9068                 
9069                 
9070         };
9071         
9072         if (this.parentType === 'Navbar' &&  this.parent().bar) {
9073            cfg.cls += ' navbar-form';
9074         }
9075         
9076         if (this.parentType === 'NavGroup') {
9077            cfg.cls += ' navbar-form';
9078            cfg.tag = 'li';
9079         }
9080         
9081         return cfg;
9082         
9083     },
9084     /**
9085      * return the real input element.
9086      */
9087     inputEl: function ()
9088     {
9089         return this.el.select('input.form-control',true).first();
9090     },
9091     
9092     tooltipEl : function()
9093     {
9094         return this.inputEl();
9095     },
9096     
9097     indicatorEl : function()
9098     {
9099         var indicator = this.el.select('i.roo-required-indicator',true).first();
9100         
9101         if(!indicator){
9102             return false;
9103         }
9104         
9105         return indicator;
9106         
9107     },
9108     
9109     setDisabled : function(v)
9110     {
9111         var i  = this.inputEl().dom;
9112         if (!v) {
9113             i.removeAttribute('disabled');
9114             return;
9115             
9116         }
9117         i.setAttribute('disabled','true');
9118     },
9119     initEvents : function()
9120     {
9121           
9122         this.inputEl().on("keydown" , this.fireKey,  this);
9123         this.inputEl().on("focus", this.onFocus,  this);
9124         this.inputEl().on("blur", this.onBlur,  this);
9125         
9126         this.inputEl().relayEvent('keyup', this);
9127         
9128         this.indicator = this.indicatorEl();
9129         
9130         if(this.indicator){
9131             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? - 
9132         }
9133  
9134         // reference to original value for reset
9135         this.originalValue = this.getValue();
9136         //Roo.form.TextField.superclass.initEvents.call(this);
9137         if(this.validationEvent == 'keyup'){
9138             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9139             this.inputEl().on('keyup', this.filterValidation, this);
9140         }
9141         else if(this.validationEvent !== false){
9142             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9143         }
9144         
9145         if(this.selectOnFocus){
9146             this.on("focus", this.preFocus, this);
9147             
9148         }
9149         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9150             this.inputEl().on("keypress", this.filterKeys, this);
9151         } else {
9152             this.inputEl().relayEvent('keypress', this);
9153         }
9154        /* if(this.grow){
9155             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
9156             this.el.on("click", this.autoSize,  this);
9157         }
9158         */
9159         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9160             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9161         }
9162         
9163         if (typeof(this.before) == 'object') {
9164             this.before.render(this.el.select('.roo-input-before',true).first());
9165         }
9166         if (typeof(this.after) == 'object') {
9167             this.after.render(this.el.select('.roo-input-after',true).first());
9168         }
9169         
9170         this.inputEl().on('change', this.onChange, this);
9171         
9172     },
9173     filterValidation : function(e){
9174         if(!e.isNavKeyPress()){
9175             this.validationTask.delay(this.validationDelay);
9176         }
9177     },
9178      /**
9179      * Validates the field value
9180      * @return {Boolean} True if the value is valid, else false
9181      */
9182     validate : function(){
9183         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9184         if(this.disabled || this.validateValue(this.getRawValue())){
9185             this.markValid();
9186             return true;
9187         }
9188         
9189         this.markInvalid();
9190         return false;
9191     },
9192     
9193     
9194     /**
9195      * Validates a value according to the field's validation rules and marks the field as invalid
9196      * if the validation fails
9197      * @param {Mixed} value The value to validate
9198      * @return {Boolean} True if the value is valid, else false
9199      */
9200     validateValue : function(value)
9201     {
9202         if(this.getVisibilityEl().hasClass('hidden')){
9203             return true;
9204         }
9205         
9206         if(value.length < 1)  { // if it's blank
9207             if(this.allowBlank){
9208                 return true;
9209             }
9210             return false;
9211         }
9212         
9213         if(value.length < this.minLength){
9214             return false;
9215         }
9216         if(value.length > this.maxLength){
9217             return false;
9218         }
9219         if(this.vtype){
9220             var vt = Roo.form.VTypes;
9221             if(!vt[this.vtype](value, this)){
9222                 return false;
9223             }
9224         }
9225         if(typeof this.validator == "function"){
9226             var msg = this.validator(value);
9227             if(msg !== true){
9228                 return false;
9229             }
9230             if (typeof(msg) == 'string') {
9231                 this.invalidText = msg;
9232             }
9233         }
9234         
9235         if(this.regex && !this.regex.test(value)){
9236             return false;
9237         }
9238         
9239         return true;
9240     },
9241     
9242      // private
9243     fireKey : function(e){
9244         //Roo.log('field ' + e.getKey());
9245         if(e.isNavKeyPress()){
9246             this.fireEvent("specialkey", this, e);
9247         }
9248     },
9249     focus : function (selectText){
9250         if(this.rendered){
9251             this.inputEl().focus();
9252             if(selectText === true){
9253                 this.inputEl().dom.select();
9254             }
9255         }
9256         return this;
9257     } ,
9258     
9259     onFocus : function(){
9260         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9261            // this.el.addClass(this.focusClass);
9262         }
9263         if(!this.hasFocus){
9264             this.hasFocus = true;
9265             this.startValue = this.getValue();
9266             this.fireEvent("focus", this);
9267         }
9268     },
9269     
9270     beforeBlur : Roo.emptyFn,
9271
9272     
9273     // private
9274     onBlur : function(){
9275         this.beforeBlur();
9276         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9277             //this.el.removeClass(this.focusClass);
9278         }
9279         this.hasFocus = false;
9280         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9281             this.validate();
9282         }
9283         var v = this.getValue();
9284         if(String(v) !== String(this.startValue)){
9285             this.fireEvent('change', this, v, this.startValue);
9286         }
9287         this.fireEvent("blur", this);
9288     },
9289     
9290     onChange : function(e)
9291     {
9292         var v = this.getValue();
9293         if(String(v) !== String(this.startValue)){
9294             this.fireEvent('change', this, v, this.startValue);
9295         }
9296         
9297     },
9298     
9299     /**
9300      * Resets the current field value to the originally loaded value and clears any validation messages
9301      */
9302     reset : function(){
9303         this.setValue(this.originalValue);
9304         this.validate();
9305     },
9306      /**
9307      * Returns the name of the field
9308      * @return {Mixed} name The name field
9309      */
9310     getName: function(){
9311         return this.name;
9312     },
9313      /**
9314      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
9315      * @return {Mixed} value The field value
9316      */
9317     getValue : function(){
9318         
9319         var v = this.inputEl().getValue();
9320         
9321         return v;
9322     },
9323     /**
9324      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
9325      * @return {Mixed} value The field value
9326      */
9327     getRawValue : function(){
9328         var v = this.inputEl().getValue();
9329         
9330         return v;
9331     },
9332     
9333     /**
9334      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
9335      * @param {Mixed} value The value to set
9336      */
9337     setRawValue : function(v){
9338         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9339     },
9340     
9341     selectText : function(start, end){
9342         var v = this.getRawValue();
9343         if(v.length > 0){
9344             start = start === undefined ? 0 : start;
9345             end = end === undefined ? v.length : end;
9346             var d = this.inputEl().dom;
9347             if(d.setSelectionRange){
9348                 d.setSelectionRange(start, end);
9349             }else if(d.createTextRange){
9350                 var range = d.createTextRange();
9351                 range.moveStart("character", start);
9352                 range.moveEnd("character", v.length-end);
9353                 range.select();
9354             }
9355         }
9356     },
9357     
9358     /**
9359      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
9360      * @param {Mixed} value The value to set
9361      */
9362     setValue : function(v){
9363         this.value = v;
9364         if(this.rendered){
9365             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9366             this.validate();
9367         }
9368     },
9369     
9370     /*
9371     processValue : function(value){
9372         if(this.stripCharsRe){
9373             var newValue = value.replace(this.stripCharsRe, '');
9374             if(newValue !== value){
9375                 this.setRawValue(newValue);
9376                 return newValue;
9377             }
9378         }
9379         return value;
9380     },
9381   */
9382     preFocus : function(){
9383         
9384         if(this.selectOnFocus){
9385             this.inputEl().dom.select();
9386         }
9387     },
9388     filterKeys : function(e){
9389         var k = e.getKey();
9390         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9391             return;
9392         }
9393         var c = e.getCharCode(), cc = String.fromCharCode(c);
9394         if(Roo.isIE && (e.isSpecialKey() || !cc)){
9395             return;
9396         }
9397         if(!this.maskRe.test(cc)){
9398             e.stopEvent();
9399         }
9400     },
9401      /**
9402      * Clear any invalid styles/messages for this field
9403      */
9404     clearInvalid : function(){
9405         
9406         if(!this.el || this.preventMark){ // not rendered
9407             return;
9408         }
9409         
9410      
9411         this.el.removeClass(this.invalidClass);
9412         
9413         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9414             
9415             var feedback = this.el.select('.form-control-feedback', true).first();
9416             
9417             if(feedback){
9418                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9419             }
9420             
9421         }
9422         
9423         if(this.indicator){
9424             this.indicator.removeClass('visible');
9425             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9426         }
9427         
9428         this.fireEvent('valid', this);
9429     },
9430     
9431      /**
9432      * Mark this field as valid
9433      */
9434     markValid : function()
9435     {
9436         if(!this.el  || this.preventMark){ // not rendered...
9437             return;
9438         }
9439         
9440         this.el.removeClass([this.invalidClass, this.validClass]);
9441         
9442         var feedback = this.el.select('.form-control-feedback', true).first();
9443             
9444         if(feedback){
9445             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9446         }
9447         
9448         if(this.indicator){
9449             this.indicator.removeClass('visible');
9450             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9451         }
9452         
9453         if(this.disabled){
9454             return;
9455         }
9456         
9457         if(this.allowBlank && !this.getRawValue().length){
9458             return;
9459         }
9460         
9461         this.el.addClass(this.validClass);
9462         
9463         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9464             
9465             var feedback = this.el.select('.form-control-feedback', true).first();
9466             
9467             if(feedback){
9468                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9469                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9470             }
9471             
9472         }
9473         
9474         this.fireEvent('valid', this);
9475     },
9476     
9477      /**
9478      * Mark this field as invalid
9479      * @param {String} msg The validation message
9480      */
9481     markInvalid : function(msg)
9482     {
9483         if(!this.el  || this.preventMark){ // not rendered
9484             return;
9485         }
9486         
9487         this.el.removeClass([this.invalidClass, this.validClass]);
9488         
9489         var feedback = this.el.select('.form-control-feedback', true).first();
9490             
9491         if(feedback){
9492             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9493         }
9494
9495         if(this.disabled){
9496             return;
9497         }
9498         
9499         if(this.allowBlank && !this.getRawValue().length){
9500             return;
9501         }
9502         
9503         if(this.indicator){
9504             this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9505             this.indicator.addClass('visible');
9506         }
9507         
9508         this.el.addClass(this.invalidClass);
9509         
9510         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9511             
9512             var feedback = this.el.select('.form-control-feedback', true).first();
9513             
9514             if(feedback){
9515                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9516                 
9517                 if(this.getValue().length || this.forceFeedback){
9518                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9519                 }
9520                 
9521             }
9522             
9523         }
9524         
9525         this.fireEvent('invalid', this, msg);
9526     },
9527     // private
9528     SafariOnKeyDown : function(event)
9529     {
9530         // this is a workaround for a password hang bug on chrome/ webkit.
9531         if (this.inputEl().dom.type != 'password') {
9532             return;
9533         }
9534         
9535         var isSelectAll = false;
9536         
9537         if(this.inputEl().dom.selectionEnd > 0){
9538             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9539         }
9540         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9541             event.preventDefault();
9542             this.setValue('');
9543             return;
9544         }
9545         
9546         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9547             
9548             event.preventDefault();
9549             // this is very hacky as keydown always get's upper case.
9550             //
9551             var cc = String.fromCharCode(event.getCharCode());
9552             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
9553             
9554         }
9555     },
9556     adjustWidth : function(tag, w){
9557         tag = tag.toLowerCase();
9558         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9559             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9560                 if(tag == 'input'){
9561                     return w + 2;
9562                 }
9563                 if(tag == 'textarea'){
9564                     return w-2;
9565                 }
9566             }else if(Roo.isOpera){
9567                 if(tag == 'input'){
9568                     return w + 2;
9569                 }
9570                 if(tag == 'textarea'){
9571                     return w-2;
9572                 }
9573             }
9574         }
9575         return w;
9576     },
9577     
9578     setFieldLabel : function(v)
9579     {
9580         if(!this.rendered){
9581             return;
9582         }
9583         
9584         if(this.indicator){
9585             var ar = this.el.select('label > span',true);
9586             
9587             if (ar.elements.length) {
9588                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9589                 this.fieldLabel = v;
9590                 return;
9591             }
9592             
9593             var br = this.el.select('label',true);
9594             
9595             if(br.elements.length) {
9596                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9597                 this.fieldLabel = v;
9598                 return;
9599             }
9600             
9601             Roo.log('Cannot Found any of label > span || label in input');
9602             return;
9603         }
9604         
9605         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9606         this.fieldLabel = v;
9607         
9608         
9609     }
9610 });
9611
9612  
9613 /*
9614  * - LGPL
9615  *
9616  * Input
9617  * 
9618  */
9619
9620 /**
9621  * @class Roo.bootstrap.TextArea
9622  * @extends Roo.bootstrap.Input
9623  * Bootstrap TextArea class
9624  * @cfg {Number} cols Specifies the visible width of a text area
9625  * @cfg {Number} rows Specifies the visible number of lines in a text area
9626  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9627  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9628  * @cfg {string} html text
9629  * 
9630  * @constructor
9631  * Create a new TextArea
9632  * @param {Object} config The config object
9633  */
9634
9635 Roo.bootstrap.TextArea = function(config){
9636     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9637    
9638 };
9639
9640 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
9641      
9642     cols : false,
9643     rows : 5,
9644     readOnly : false,
9645     warp : 'soft',
9646     resize : false,
9647     value: false,
9648     html: false,
9649     
9650     getAutoCreate : function(){
9651         
9652         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9653         
9654         var id = Roo.id();
9655         
9656         var cfg = {};
9657         
9658         if(this.inputType != 'hidden'){
9659             cfg.cls = 'form-group' //input-group
9660         }
9661         
9662         var input =  {
9663             tag: 'textarea',
9664             id : id,
9665             warp : this.warp,
9666             rows : this.rows,
9667             value : this.value || '',
9668             html: this.html || '',
9669             cls : 'form-control',
9670             placeholder : this.placeholder || '' 
9671             
9672         };
9673         
9674         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9675             input.maxLength = this.maxLength;
9676         }
9677         
9678         if(this.resize){
9679             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9680         }
9681         
9682         if(this.cols){
9683             input.cols = this.cols;
9684         }
9685         
9686         if (this.readOnly) {
9687             input.readonly = true;
9688         }
9689         
9690         if (this.name) {
9691             input.name = this.name;
9692         }
9693         
9694         if (this.size) {
9695             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9696         }
9697         
9698         var settings=this;
9699         ['xs','sm','md','lg'].map(function(size){
9700             if (settings[size]) {
9701                 cfg.cls += ' col-' + size + '-' + settings[size];
9702             }
9703         });
9704         
9705         var inputblock = input;
9706         
9707         if(this.hasFeedback && !this.allowBlank){
9708             
9709             var feedback = {
9710                 tag: 'span',
9711                 cls: 'glyphicon form-control-feedback'
9712             };
9713
9714             inputblock = {
9715                 cls : 'has-feedback',
9716                 cn :  [
9717                     input,
9718                     feedback
9719                 ] 
9720             };  
9721         }
9722         
9723         
9724         if (this.before || this.after) {
9725             
9726             inputblock = {
9727                 cls : 'input-group',
9728                 cn :  [] 
9729             };
9730             if (this.before) {
9731                 inputblock.cn.push({
9732                     tag :'span',
9733                     cls : 'input-group-addon',
9734                     html : this.before
9735                 });
9736             }
9737             
9738             inputblock.cn.push(input);
9739             
9740             if(this.hasFeedback && !this.allowBlank){
9741                 inputblock.cls += ' has-feedback';
9742                 inputblock.cn.push(feedback);
9743             }
9744             
9745             if (this.after) {
9746                 inputblock.cn.push({
9747                     tag :'span',
9748                     cls : 'input-group-addon',
9749                     html : this.after
9750                 });
9751             }
9752             
9753         }
9754         
9755         if (align ==='left' && this.fieldLabel.length) {
9756             cfg.cn = [
9757                 {
9758                     tag: 'label',
9759                     'for' :  id,
9760                     cls : 'control-label',
9761                     html : this.fieldLabel
9762                 },
9763                 {
9764                     cls : "",
9765                     cn: [
9766                         inputblock
9767                     ]
9768                 }
9769
9770             ];
9771             
9772             if(this.labelWidth > 12){
9773                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9774             }
9775
9776             if(this.labelWidth < 13 && this.labelmd == 0){
9777                 this.labelmd = this.labelWidth;
9778             }
9779
9780             if(this.labellg > 0){
9781                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9782                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9783             }
9784
9785             if(this.labelmd > 0){
9786                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9787                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9788             }
9789
9790             if(this.labelsm > 0){
9791                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9792                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9793             }
9794
9795             if(this.labelxs > 0){
9796                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9797                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9798             }
9799             
9800         } else if ( this.fieldLabel.length) {
9801             cfg.cn = [
9802
9803                {
9804                    tag: 'label',
9805                    //cls : 'input-group-addon',
9806                    html : this.fieldLabel
9807
9808                },
9809
9810                inputblock
9811
9812            ];
9813
9814         } else {
9815
9816             cfg.cn = [
9817
9818                 inputblock
9819
9820             ];
9821                 
9822         }
9823         
9824         if (this.disabled) {
9825             input.disabled=true;
9826         }
9827         
9828         return cfg;
9829         
9830     },
9831     /**
9832      * return the real textarea element.
9833      */
9834     inputEl: function ()
9835     {
9836         return this.el.select('textarea.form-control',true).first();
9837     },
9838     
9839     /**
9840      * Clear any invalid styles/messages for this field
9841      */
9842     clearInvalid : function()
9843     {
9844         
9845         if(!this.el || this.preventMark){ // not rendered
9846             return;
9847         }
9848         
9849         var label = this.el.select('label', true).first();
9850         var icon = this.el.select('i.fa-star', true).first();
9851         
9852         if(label && icon){
9853             icon.remove();
9854         }
9855         
9856         this.el.removeClass(this.invalidClass);
9857         
9858         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9859             
9860             var feedback = this.el.select('.form-control-feedback', true).first();
9861             
9862             if(feedback){
9863                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9864             }
9865             
9866         }
9867         
9868         this.fireEvent('valid', this);
9869     },
9870     
9871      /**
9872      * Mark this field as valid
9873      */
9874     markValid : function()
9875     {
9876         if(!this.el  || this.preventMark){ // not rendered
9877             return;
9878         }
9879         
9880         this.el.removeClass([this.invalidClass, this.validClass]);
9881         
9882         var feedback = this.el.select('.form-control-feedback', true).first();
9883             
9884         if(feedback){
9885             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9886         }
9887
9888         if(this.disabled || this.allowBlank){
9889             return;
9890         }
9891         
9892         var label = this.el.select('label', true).first();
9893         var icon = this.el.select('i.fa-star', true).first();
9894         
9895         if(label && icon){
9896             icon.remove();
9897         }
9898         
9899         this.el.addClass(this.validClass);
9900         
9901         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9902             
9903             var feedback = this.el.select('.form-control-feedback', true).first();
9904             
9905             if(feedback){
9906                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9907                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9908             }
9909             
9910         }
9911         
9912         this.fireEvent('valid', this);
9913     },
9914     
9915      /**
9916      * Mark this field as invalid
9917      * @param {String} msg The validation message
9918      */
9919     markInvalid : function(msg)
9920     {
9921         if(!this.el  || this.preventMark){ // not rendered
9922             return;
9923         }
9924         
9925         this.el.removeClass([this.invalidClass, this.validClass]);
9926         
9927         var feedback = this.el.select('.form-control-feedback', true).first();
9928             
9929         if(feedback){
9930             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9931         }
9932
9933         if(this.disabled || this.allowBlank){
9934             return;
9935         }
9936         
9937         var label = this.el.select('label', true).first();
9938         var icon = this.el.select('i.fa-star', true).first();
9939         
9940         if(!this.getValue().length && label && !icon){
9941             this.el.createChild({
9942                 tag : 'i',
9943                 cls : 'text-danger fa fa-lg fa-star',
9944                 tooltip : 'This field is required',
9945                 style : 'margin-right:5px;'
9946             }, label, true);
9947         }
9948
9949         this.el.addClass(this.invalidClass);
9950         
9951         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9952             
9953             var feedback = this.el.select('.form-control-feedback', true).first();
9954             
9955             if(feedback){
9956                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9957                 
9958                 if(this.getValue().length || this.forceFeedback){
9959                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9960                 }
9961                 
9962             }
9963             
9964         }
9965         
9966         this.fireEvent('invalid', this, msg);
9967     }
9968 });
9969
9970  
9971 /*
9972  * - LGPL
9973  *
9974  * trigger field - base class for combo..
9975  * 
9976  */
9977  
9978 /**
9979  * @class Roo.bootstrap.TriggerField
9980  * @extends Roo.bootstrap.Input
9981  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9982  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9983  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9984  * for which you can provide a custom implementation.  For example:
9985  * <pre><code>
9986 var trigger = new Roo.bootstrap.TriggerField();
9987 trigger.onTriggerClick = myTriggerFn;
9988 trigger.applyTo('my-field');
9989 </code></pre>
9990  *
9991  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9992  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9993  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
9994  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9995  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9996
9997  * @constructor
9998  * Create a new TriggerField.
9999  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10000  * to the base TextField)
10001  */
10002 Roo.bootstrap.TriggerField = function(config){
10003     this.mimicing = false;
10004     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10005 };
10006
10007 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
10008     /**
10009      * @cfg {String} triggerClass A CSS class to apply to the trigger
10010      */
10011      /**
10012      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10013      */
10014     hideTrigger:false,
10015
10016     /**
10017      * @cfg {Boolean} removable (true|false) special filter default false
10018      */
10019     removable : false,
10020     
10021     /** @cfg {Boolean} grow @hide */
10022     /** @cfg {Number} growMin @hide */
10023     /** @cfg {Number} growMax @hide */
10024
10025     /**
10026      * @hide 
10027      * @method
10028      */
10029     autoSize: Roo.emptyFn,
10030     // private
10031     monitorTab : true,
10032     // private
10033     deferHeight : true,
10034
10035     
10036     actionMode : 'wrap',
10037     
10038     caret : false,
10039     
10040     
10041     getAutoCreate : function(){
10042        
10043         var align = this.labelAlign || this.parentLabelAlign();
10044         
10045         var id = Roo.id();
10046         
10047         var cfg = {
10048             cls: 'form-group' //input-group
10049         };
10050         
10051         
10052         var input =  {
10053             tag: 'input',
10054             id : id,
10055             type : this.inputType,
10056             cls : 'form-control',
10057             autocomplete: 'new-password',
10058             placeholder : this.placeholder || '' 
10059             
10060         };
10061         if (this.name) {
10062             input.name = this.name;
10063         }
10064         if (this.size) {
10065             input.cls += ' input-' + this.size;
10066         }
10067         
10068         if (this.disabled) {
10069             input.disabled=true;
10070         }
10071         
10072         var inputblock = input;
10073         
10074         if(this.hasFeedback && !this.allowBlank){
10075             
10076             var feedback = {
10077                 tag: 'span',
10078                 cls: 'glyphicon form-control-feedback'
10079             };
10080             
10081             if(this.removable && !this.editable && !this.tickable){
10082                 inputblock = {
10083                     cls : 'has-feedback',
10084                     cn :  [
10085                         inputblock,
10086                         {
10087                             tag: 'button',
10088                             html : 'x',
10089                             cls : 'roo-combo-removable-btn close'
10090                         },
10091                         feedback
10092                     ] 
10093                 };
10094             } else {
10095                 inputblock = {
10096                     cls : 'has-feedback',
10097                     cn :  [
10098                         inputblock,
10099                         feedback
10100                     ] 
10101                 };
10102             }
10103
10104         } else {
10105             if(this.removable && !this.editable && !this.tickable){
10106                 inputblock = {
10107                     cls : 'roo-removable',
10108                     cn :  [
10109                         inputblock,
10110                         {
10111                             tag: 'button',
10112                             html : 'x',
10113                             cls : 'roo-combo-removable-btn close'
10114                         }
10115                     ] 
10116                 };
10117             }
10118         }
10119         
10120         if (this.before || this.after) {
10121             
10122             inputblock = {
10123                 cls : 'input-group',
10124                 cn :  [] 
10125             };
10126             if (this.before) {
10127                 inputblock.cn.push({
10128                     tag :'span',
10129                     cls : 'input-group-addon',
10130                     html : this.before
10131                 });
10132             }
10133             
10134             inputblock.cn.push(input);
10135             
10136             if(this.hasFeedback && !this.allowBlank){
10137                 inputblock.cls += ' has-feedback';
10138                 inputblock.cn.push(feedback);
10139             }
10140             
10141             if (this.after) {
10142                 inputblock.cn.push({
10143                     tag :'span',
10144                     cls : 'input-group-addon',
10145                     html : this.after
10146                 });
10147             }
10148             
10149         };
10150         
10151         var box = {
10152             tag: 'div',
10153             cn: [
10154                 {
10155                     tag: 'input',
10156                     type : 'hidden',
10157                     cls: 'form-hidden-field'
10158                 },
10159                 inputblock
10160             ]
10161             
10162         };
10163         
10164         if(this.multiple){
10165             box = {
10166                 tag: 'div',
10167                 cn: [
10168                     {
10169                         tag: 'input',
10170                         type : 'hidden',
10171                         cls: 'form-hidden-field'
10172                     },
10173                     {
10174                         tag: 'ul',
10175                         cls: 'roo-select2-choices',
10176                         cn:[
10177                             {
10178                                 tag: 'li',
10179                                 cls: 'roo-select2-search-field',
10180                                 cn: [
10181
10182                                     inputblock
10183                                 ]
10184                             }
10185                         ]
10186                     }
10187                 ]
10188             }
10189         };
10190         
10191         var combobox = {
10192             cls: 'roo-select2-container input-group',
10193             cn: [
10194                 box
10195 //                {
10196 //                    tag: 'ul',
10197 //                    cls: 'typeahead typeahead-long dropdown-menu',
10198 //                    style: 'display:none'
10199 //                }
10200             ]
10201         };
10202         
10203         if(!this.multiple && this.showToggleBtn){
10204             
10205             var caret = {
10206                         tag: 'span',
10207                         cls: 'caret'
10208              };
10209             if (this.caret != false) {
10210                 caret = {
10211                      tag: 'i',
10212                      cls: 'fa fa-' + this.caret
10213                 };
10214                 
10215             }
10216             
10217             combobox.cn.push({
10218                 tag :'span',
10219                 cls : 'input-group-addon btn dropdown-toggle',
10220                 cn : [
10221                     caret,
10222                     {
10223                         tag: 'span',
10224                         cls: 'combobox-clear',
10225                         cn  : [
10226                             {
10227                                 tag : 'i',
10228                                 cls: 'icon-remove'
10229                             }
10230                         ]
10231                     }
10232                 ]
10233
10234             })
10235         }
10236         
10237         if(this.multiple){
10238             combobox.cls += ' roo-select2-container-multi';
10239         }
10240         
10241         if (align ==='left' && this.fieldLabel.length) {
10242             
10243             cfg.cls += ' roo-form-group-label-left';
10244
10245             cfg.cn = [
10246                 {
10247                     tag : 'i',
10248                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10249                     tooltip : 'This field is required'
10250                 },
10251                 {
10252                     tag: 'label',
10253                     'for' :  id,
10254                     cls : 'control-label',
10255                     html : this.fieldLabel
10256
10257                 },
10258                 {
10259                     cls : "", 
10260                     cn: [
10261                         combobox
10262                     ]
10263                 }
10264
10265             ];
10266             
10267             var labelCfg = cfg.cn[1];
10268             var contentCfg = cfg.cn[2];
10269             
10270             if(this.indicatorpos == 'right'){
10271                 cfg.cn = [
10272                     {
10273                         tag: 'label',
10274                         'for' :  id,
10275                         cls : 'control-label',
10276                         cn : [
10277                             {
10278                                 tag : 'span',
10279                                 html : this.fieldLabel
10280                             },
10281                             {
10282                                 tag : 'i',
10283                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10284                                 tooltip : 'This field is required'
10285                             }
10286                         ]
10287                     },
10288                     {
10289                         cls : "", 
10290                         cn: [
10291                             combobox
10292                         ]
10293                     }
10294
10295                 ];
10296                 
10297                 labelCfg = cfg.cn[0];
10298                 contentCfg = cfg.cn[1];
10299             }
10300             
10301             if(this.labelWidth > 12){
10302                 labelCfg.style = "width: " + this.labelWidth + 'px';
10303             }
10304             
10305             if(this.labelWidth < 13 && this.labelmd == 0){
10306                 this.labelmd = this.labelWidth;
10307             }
10308             
10309             if(this.labellg > 0){
10310                 labelCfg.cls += ' col-lg-' + this.labellg;
10311                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10312             }
10313             
10314             if(this.labelmd > 0){
10315                 labelCfg.cls += ' col-md-' + this.labelmd;
10316                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10317             }
10318             
10319             if(this.labelsm > 0){
10320                 labelCfg.cls += ' col-sm-' + this.labelsm;
10321                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10322             }
10323             
10324             if(this.labelxs > 0){
10325                 labelCfg.cls += ' col-xs-' + this.labelxs;
10326                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10327             }
10328             
10329         } else if ( this.fieldLabel.length) {
10330 //                Roo.log(" label");
10331             cfg.cn = [
10332                 {
10333                    tag : 'i',
10334                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10335                    tooltip : 'This field is required'
10336                },
10337                {
10338                    tag: 'label',
10339                    //cls : 'input-group-addon',
10340                    html : this.fieldLabel
10341
10342                },
10343
10344                combobox
10345
10346             ];
10347             
10348             if(this.indicatorpos == 'right'){
10349                 
10350                 cfg.cn = [
10351                     {
10352                        tag: 'label',
10353                        cn : [
10354                            {
10355                                tag : 'span',
10356                                html : this.fieldLabel
10357                            },
10358                            {
10359                               tag : 'i',
10360                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10361                               tooltip : 'This field is required'
10362                            }
10363                        ]
10364
10365                     },
10366                     combobox
10367
10368                 ];
10369
10370             }
10371
10372         } else {
10373             
10374 //                Roo.log(" no label && no align");
10375                 cfg = combobox
10376                      
10377                 
10378         }
10379         
10380         var settings=this;
10381         ['xs','sm','md','lg'].map(function(size){
10382             if (settings[size]) {
10383                 cfg.cls += ' col-' + size + '-' + settings[size];
10384             }
10385         });
10386         
10387         return cfg;
10388         
10389     },
10390     
10391     
10392     
10393     // private
10394     onResize : function(w, h){
10395 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10396 //        if(typeof w == 'number'){
10397 //            var x = w - this.trigger.getWidth();
10398 //            this.inputEl().setWidth(this.adjustWidth('input', x));
10399 //            this.trigger.setStyle('left', x+'px');
10400 //        }
10401     },
10402
10403     // private
10404     adjustSize : Roo.BoxComponent.prototype.adjustSize,
10405
10406     // private
10407     getResizeEl : function(){
10408         return this.inputEl();
10409     },
10410
10411     // private
10412     getPositionEl : function(){
10413         return this.inputEl();
10414     },
10415
10416     // private
10417     alignErrorIcon : function(){
10418         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10419     },
10420
10421     // private
10422     initEvents : function(){
10423         
10424         this.createList();
10425         
10426         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10427         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10428         if(!this.multiple && this.showToggleBtn){
10429             this.trigger = this.el.select('span.dropdown-toggle',true).first();
10430             if(this.hideTrigger){
10431                 this.trigger.setDisplayed(false);
10432             }
10433             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10434         }
10435         
10436         if(this.multiple){
10437             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10438         }
10439         
10440         if(this.removable && !this.editable && !this.tickable){
10441             var close = this.closeTriggerEl();
10442             
10443             if(close){
10444                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10445                 close.on('click', this.removeBtnClick, this, close);
10446             }
10447         }
10448         
10449         //this.trigger.addClassOnOver('x-form-trigger-over');
10450         //this.trigger.addClassOnClick('x-form-trigger-click');
10451         
10452         //if(!this.width){
10453         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10454         //}
10455     },
10456     
10457     closeTriggerEl : function()
10458     {
10459         var close = this.el.select('.roo-combo-removable-btn', true).first();
10460         return close ? close : false;
10461     },
10462     
10463     removeBtnClick : function(e, h, el)
10464     {
10465         e.preventDefault();
10466         
10467         if(this.fireEvent("remove", this) !== false){
10468             this.reset();
10469             this.fireEvent("afterremove", this)
10470         }
10471     },
10472     
10473     createList : function()
10474     {
10475         this.list = Roo.get(document.body).createChild({
10476             tag: 'ul',
10477             cls: 'typeahead typeahead-long dropdown-menu',
10478             style: 'display:none'
10479         });
10480         
10481         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10482         
10483     },
10484
10485     // private
10486     initTrigger : function(){
10487        
10488     },
10489
10490     // private
10491     onDestroy : function(){
10492         if(this.trigger){
10493             this.trigger.removeAllListeners();
10494           //  this.trigger.remove();
10495         }
10496         //if(this.wrap){
10497         //    this.wrap.remove();
10498         //}
10499         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10500     },
10501
10502     // private
10503     onFocus : function(){
10504         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10505         /*
10506         if(!this.mimicing){
10507             this.wrap.addClass('x-trigger-wrap-focus');
10508             this.mimicing = true;
10509             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10510             if(this.monitorTab){
10511                 this.el.on("keydown", this.checkTab, this);
10512             }
10513         }
10514         */
10515     },
10516
10517     // private
10518     checkTab : function(e){
10519         if(e.getKey() == e.TAB){
10520             this.triggerBlur();
10521         }
10522     },
10523
10524     // private
10525     onBlur : function(){
10526         // do nothing
10527     },
10528
10529     // private
10530     mimicBlur : function(e, t){
10531         /*
10532         if(!this.wrap.contains(t) && this.validateBlur()){
10533             this.triggerBlur();
10534         }
10535         */
10536     },
10537
10538     // private
10539     triggerBlur : function(){
10540         this.mimicing = false;
10541         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10542         if(this.monitorTab){
10543             this.el.un("keydown", this.checkTab, this);
10544         }
10545         //this.wrap.removeClass('x-trigger-wrap-focus');
10546         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10547     },
10548
10549     // private
10550     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10551     validateBlur : function(e, t){
10552         return true;
10553     },
10554
10555     // private
10556     onDisable : function(){
10557         this.inputEl().dom.disabled = true;
10558         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10559         //if(this.wrap){
10560         //    this.wrap.addClass('x-item-disabled');
10561         //}
10562     },
10563
10564     // private
10565     onEnable : function(){
10566         this.inputEl().dom.disabled = false;
10567         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10568         //if(this.wrap){
10569         //    this.el.removeClass('x-item-disabled');
10570         //}
10571     },
10572
10573     // private
10574     onShow : function(){
10575         var ae = this.getActionEl();
10576         
10577         if(ae){
10578             ae.dom.style.display = '';
10579             ae.dom.style.visibility = 'visible';
10580         }
10581     },
10582
10583     // private
10584     
10585     onHide : function(){
10586         var ae = this.getActionEl();
10587         ae.dom.style.display = 'none';
10588     },
10589
10590     /**
10591      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
10592      * by an implementing function.
10593      * @method
10594      * @param {EventObject} e
10595      */
10596     onTriggerClick : Roo.emptyFn
10597 });
10598  /*
10599  * Based on:
10600  * Ext JS Library 1.1.1
10601  * Copyright(c) 2006-2007, Ext JS, LLC.
10602  *
10603  * Originally Released Under LGPL - original licence link has changed is not relivant.
10604  *
10605  * Fork - LGPL
10606  * <script type="text/javascript">
10607  */
10608
10609
10610 /**
10611  * @class Roo.data.SortTypes
10612  * @singleton
10613  * Defines the default sorting (casting?) comparison functions used when sorting data.
10614  */
10615 Roo.data.SortTypes = {
10616     /**
10617      * Default sort that does nothing
10618      * @param {Mixed} s The value being converted
10619      * @return {Mixed} The comparison value
10620      */
10621     none : function(s){
10622         return s;
10623     },
10624     
10625     /**
10626      * The regular expression used to strip tags
10627      * @type {RegExp}
10628      * @property
10629      */
10630     stripTagsRE : /<\/?[^>]+>/gi,
10631     
10632     /**
10633      * Strips all HTML tags to sort on text only
10634      * @param {Mixed} s The value being converted
10635      * @return {String} The comparison value
10636      */
10637     asText : function(s){
10638         return String(s).replace(this.stripTagsRE, "");
10639     },
10640     
10641     /**
10642      * Strips all HTML tags to sort on text only - Case insensitive
10643      * @param {Mixed} s The value being converted
10644      * @return {String} The comparison value
10645      */
10646     asUCText : function(s){
10647         return String(s).toUpperCase().replace(this.stripTagsRE, "");
10648     },
10649     
10650     /**
10651      * Case insensitive string
10652      * @param {Mixed} s The value being converted
10653      * @return {String} The comparison value
10654      */
10655     asUCString : function(s) {
10656         return String(s).toUpperCase();
10657     },
10658     
10659     /**
10660      * Date sorting
10661      * @param {Mixed} s The value being converted
10662      * @return {Number} The comparison value
10663      */
10664     asDate : function(s) {
10665         if(!s){
10666             return 0;
10667         }
10668         if(s instanceof Date){
10669             return s.getTime();
10670         }
10671         return Date.parse(String(s));
10672     },
10673     
10674     /**
10675      * Float sorting
10676      * @param {Mixed} s The value being converted
10677      * @return {Float} The comparison value
10678      */
10679     asFloat : function(s) {
10680         var val = parseFloat(String(s).replace(/,/g, ""));
10681         if(isNaN(val)) {
10682             val = 0;
10683         }
10684         return val;
10685     },
10686     
10687     /**
10688      * Integer sorting
10689      * @param {Mixed} s The value being converted
10690      * @return {Number} The comparison value
10691      */
10692     asInt : function(s) {
10693         var val = parseInt(String(s).replace(/,/g, ""));
10694         if(isNaN(val)) {
10695             val = 0;
10696         }
10697         return val;
10698     }
10699 };/*
10700  * Based on:
10701  * Ext JS Library 1.1.1
10702  * Copyright(c) 2006-2007, Ext JS, LLC.
10703  *
10704  * Originally Released Under LGPL - original licence link has changed is not relivant.
10705  *
10706  * Fork - LGPL
10707  * <script type="text/javascript">
10708  */
10709
10710 /**
10711 * @class Roo.data.Record
10712  * Instances of this class encapsulate both record <em>definition</em> information, and record
10713  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10714  * to access Records cached in an {@link Roo.data.Store} object.<br>
10715  * <p>
10716  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10717  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10718  * objects.<br>
10719  * <p>
10720  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10721  * @constructor
10722  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10723  * {@link #create}. The parameters are the same.
10724  * @param {Array} data An associative Array of data values keyed by the field name.
10725  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10726  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10727  * not specified an integer id is generated.
10728  */
10729 Roo.data.Record = function(data, id){
10730     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10731     this.data = data;
10732 };
10733
10734 /**
10735  * Generate a constructor for a specific record layout.
10736  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10737  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10738  * Each field definition object may contain the following properties: <ul>
10739  * <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,
10740  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10741  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10742  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10743  * is being used, then this is a string containing the javascript expression to reference the data relative to 
10744  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10745  * to the data item relative to the record element. If the mapping expression is the same as the field name,
10746  * this may be omitted.</p></li>
10747  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10748  * <ul><li>auto (Default, implies no conversion)</li>
10749  * <li>string</li>
10750  * <li>int</li>
10751  * <li>float</li>
10752  * <li>boolean</li>
10753  * <li>date</li></ul></p></li>
10754  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10755  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10756  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10757  * by the Reader into an object that will be stored in the Record. It is passed the
10758  * following parameters:<ul>
10759  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10760  * </ul></p></li>
10761  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10762  * </ul>
10763  * <br>usage:<br><pre><code>
10764 var TopicRecord = Roo.data.Record.create(
10765     {name: 'title', mapping: 'topic_title'},
10766     {name: 'author', mapping: 'username'},
10767     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10768     {name: 'lastPost', mapping: 'post_time', type: 'date'},
10769     {name: 'lastPoster', mapping: 'user2'},
10770     {name: 'excerpt', mapping: 'post_text'}
10771 );
10772
10773 var myNewRecord = new TopicRecord({
10774     title: 'Do my job please',
10775     author: 'noobie',
10776     totalPosts: 1,
10777     lastPost: new Date(),
10778     lastPoster: 'Animal',
10779     excerpt: 'No way dude!'
10780 });
10781 myStore.add(myNewRecord);
10782 </code></pre>
10783  * @method create
10784  * @static
10785  */
10786 Roo.data.Record.create = function(o){
10787     var f = function(){
10788         f.superclass.constructor.apply(this, arguments);
10789     };
10790     Roo.extend(f, Roo.data.Record);
10791     var p = f.prototype;
10792     p.fields = new Roo.util.MixedCollection(false, function(field){
10793         return field.name;
10794     });
10795     for(var i = 0, len = o.length; i < len; i++){
10796         p.fields.add(new Roo.data.Field(o[i]));
10797     }
10798     f.getField = function(name){
10799         return p.fields.get(name);  
10800     };
10801     return f;
10802 };
10803
10804 Roo.data.Record.AUTO_ID = 1000;
10805 Roo.data.Record.EDIT = 'edit';
10806 Roo.data.Record.REJECT = 'reject';
10807 Roo.data.Record.COMMIT = 'commit';
10808
10809 Roo.data.Record.prototype = {
10810     /**
10811      * Readonly flag - true if this record has been modified.
10812      * @type Boolean
10813      */
10814     dirty : false,
10815     editing : false,
10816     error: null,
10817     modified: null,
10818
10819     // private
10820     join : function(store){
10821         this.store = store;
10822     },
10823
10824     /**
10825      * Set the named field to the specified value.
10826      * @param {String} name The name of the field to set.
10827      * @param {Object} value The value to set the field to.
10828      */
10829     set : function(name, value){
10830         if(this.data[name] == value){
10831             return;
10832         }
10833         this.dirty = true;
10834         if(!this.modified){
10835             this.modified = {};
10836         }
10837         if(typeof this.modified[name] == 'undefined'){
10838             this.modified[name] = this.data[name];
10839         }
10840         this.data[name] = value;
10841         if(!this.editing && this.store){
10842             this.store.afterEdit(this);
10843         }       
10844     },
10845
10846     /**
10847      * Get the value of the named field.
10848      * @param {String} name The name of the field to get the value of.
10849      * @return {Object} The value of the field.
10850      */
10851     get : function(name){
10852         return this.data[name]; 
10853     },
10854
10855     // private
10856     beginEdit : function(){
10857         this.editing = true;
10858         this.modified = {}; 
10859     },
10860
10861     // private
10862     cancelEdit : function(){
10863         this.editing = false;
10864         delete this.modified;
10865     },
10866
10867     // private
10868     endEdit : function(){
10869         this.editing = false;
10870         if(this.dirty && this.store){
10871             this.store.afterEdit(this);
10872         }
10873     },
10874
10875     /**
10876      * Usually called by the {@link Roo.data.Store} which owns the Record.
10877      * Rejects all changes made to the Record since either creation, or the last commit operation.
10878      * Modified fields are reverted to their original values.
10879      * <p>
10880      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10881      * of reject operations.
10882      */
10883     reject : function(){
10884         var m = this.modified;
10885         for(var n in m){
10886             if(typeof m[n] != "function"){
10887                 this.data[n] = m[n];
10888             }
10889         }
10890         this.dirty = false;
10891         delete this.modified;
10892         this.editing = false;
10893         if(this.store){
10894             this.store.afterReject(this);
10895         }
10896     },
10897
10898     /**
10899      * Usually called by the {@link Roo.data.Store} which owns the Record.
10900      * Commits all changes made to the Record since either creation, or the last commit operation.
10901      * <p>
10902      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10903      * of commit operations.
10904      */
10905     commit : function(){
10906         this.dirty = false;
10907         delete this.modified;
10908         this.editing = false;
10909         if(this.store){
10910             this.store.afterCommit(this);
10911         }
10912     },
10913
10914     // private
10915     hasError : function(){
10916         return this.error != null;
10917     },
10918
10919     // private
10920     clearError : function(){
10921         this.error = null;
10922     },
10923
10924     /**
10925      * Creates a copy of this record.
10926      * @param {String} id (optional) A new record id if you don't want to use this record's id
10927      * @return {Record}
10928      */
10929     copy : function(newId) {
10930         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10931     }
10932 };/*
10933  * Based on:
10934  * Ext JS Library 1.1.1
10935  * Copyright(c) 2006-2007, Ext JS, LLC.
10936  *
10937  * Originally Released Under LGPL - original licence link has changed is not relivant.
10938  *
10939  * Fork - LGPL
10940  * <script type="text/javascript">
10941  */
10942
10943
10944
10945 /**
10946  * @class Roo.data.Store
10947  * @extends Roo.util.Observable
10948  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10949  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10950  * <p>
10951  * 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
10952  * has no knowledge of the format of the data returned by the Proxy.<br>
10953  * <p>
10954  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10955  * instances from the data object. These records are cached and made available through accessor functions.
10956  * @constructor
10957  * Creates a new Store.
10958  * @param {Object} config A config object containing the objects needed for the Store to access data,
10959  * and read the data into Records.
10960  */
10961 Roo.data.Store = function(config){
10962     this.data = new Roo.util.MixedCollection(false);
10963     this.data.getKey = function(o){
10964         return o.id;
10965     };
10966     this.baseParams = {};
10967     // private
10968     this.paramNames = {
10969         "start" : "start",
10970         "limit" : "limit",
10971         "sort" : "sort",
10972         "dir" : "dir",
10973         "multisort" : "_multisort"
10974     };
10975
10976     if(config && config.data){
10977         this.inlineData = config.data;
10978         delete config.data;
10979     }
10980
10981     Roo.apply(this, config);
10982     
10983     if(this.reader){ // reader passed
10984         this.reader = Roo.factory(this.reader, Roo.data);
10985         this.reader.xmodule = this.xmodule || false;
10986         if(!this.recordType){
10987             this.recordType = this.reader.recordType;
10988         }
10989         if(this.reader.onMetaChange){
10990             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10991         }
10992     }
10993
10994     if(this.recordType){
10995         this.fields = this.recordType.prototype.fields;
10996     }
10997     this.modified = [];
10998
10999     this.addEvents({
11000         /**
11001          * @event datachanged
11002          * Fires when the data cache has changed, and a widget which is using this Store
11003          * as a Record cache should refresh its view.
11004          * @param {Store} this
11005          */
11006         datachanged : true,
11007         /**
11008          * @event metachange
11009          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11010          * @param {Store} this
11011          * @param {Object} meta The JSON metadata
11012          */
11013         metachange : true,
11014         /**
11015          * @event add
11016          * Fires when Records have been added to the Store
11017          * @param {Store} this
11018          * @param {Roo.data.Record[]} records The array of Records added
11019          * @param {Number} index The index at which the record(s) were added
11020          */
11021         add : true,
11022         /**
11023          * @event remove
11024          * Fires when a Record has been removed from the Store
11025          * @param {Store} this
11026          * @param {Roo.data.Record} record The Record that was removed
11027          * @param {Number} index The index at which the record was removed
11028          */
11029         remove : true,
11030         /**
11031          * @event update
11032          * Fires when a Record has been updated
11033          * @param {Store} this
11034          * @param {Roo.data.Record} record The Record that was updated
11035          * @param {String} operation The update operation being performed.  Value may be one of:
11036          * <pre><code>
11037  Roo.data.Record.EDIT
11038  Roo.data.Record.REJECT
11039  Roo.data.Record.COMMIT
11040          * </code></pre>
11041          */
11042         update : true,
11043         /**
11044          * @event clear
11045          * Fires when the data cache has been cleared.
11046          * @param {Store} this
11047          */
11048         clear : true,
11049         /**
11050          * @event beforeload
11051          * Fires before a request is made for a new data object.  If the beforeload handler returns false
11052          * the load action will be canceled.
11053          * @param {Store} this
11054          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11055          */
11056         beforeload : true,
11057         /**
11058          * @event beforeloadadd
11059          * Fires after a new set of Records has been loaded.
11060          * @param {Store} this
11061          * @param {Roo.data.Record[]} records The Records that were loaded
11062          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11063          */
11064         beforeloadadd : true,
11065         /**
11066          * @event load
11067          * Fires after a new set of Records has been loaded, before they are added to the store.
11068          * @param {Store} this
11069          * @param {Roo.data.Record[]} records The Records that were loaded
11070          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11071          * @params {Object} return from reader
11072          */
11073         load : true,
11074         /**
11075          * @event loadexception
11076          * Fires if an exception occurs in the Proxy during loading.
11077          * Called with the signature of the Proxy's "loadexception" event.
11078          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11079          * 
11080          * @param {Proxy} 
11081          * @param {Object} return from JsonData.reader() - success, totalRecords, records
11082          * @param {Object} load options 
11083          * @param {Object} jsonData from your request (normally this contains the Exception)
11084          */
11085         loadexception : true
11086     });
11087     
11088     if(this.proxy){
11089         this.proxy = Roo.factory(this.proxy, Roo.data);
11090         this.proxy.xmodule = this.xmodule || false;
11091         this.relayEvents(this.proxy,  ["loadexception"]);
11092     }
11093     this.sortToggle = {};
11094     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11095
11096     Roo.data.Store.superclass.constructor.call(this);
11097
11098     if(this.inlineData){
11099         this.loadData(this.inlineData);
11100         delete this.inlineData;
11101     }
11102 };
11103
11104 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11105      /**
11106     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
11107     * without a remote query - used by combo/forms at present.
11108     */
11109     
11110     /**
11111     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11112     */
11113     /**
11114     * @cfg {Array} data Inline data to be loaded when the store is initialized.
11115     */
11116     /**
11117     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11118     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11119     */
11120     /**
11121     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11122     * on any HTTP request
11123     */
11124     /**
11125     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11126     */
11127     /**
11128     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11129     */
11130     multiSort: false,
11131     /**
11132     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11133     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11134     */
11135     remoteSort : false,
11136
11137     /**
11138     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11139      * loaded or when a record is removed. (defaults to false).
11140     */
11141     pruneModifiedRecords : false,
11142
11143     // private
11144     lastOptions : null,
11145
11146     /**
11147      * Add Records to the Store and fires the add event.
11148      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11149      */
11150     add : function(records){
11151         records = [].concat(records);
11152         for(var i = 0, len = records.length; i < len; i++){
11153             records[i].join(this);
11154         }
11155         var index = this.data.length;
11156         this.data.addAll(records);
11157         this.fireEvent("add", this, records, index);
11158     },
11159
11160     /**
11161      * Remove a Record from the Store and fires the remove event.
11162      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11163      */
11164     remove : function(record){
11165         var index = this.data.indexOf(record);
11166         this.data.removeAt(index);
11167  
11168         if(this.pruneModifiedRecords){
11169             this.modified.remove(record);
11170         }
11171         this.fireEvent("remove", this, record, index);
11172     },
11173
11174     /**
11175      * Remove all Records from the Store and fires the clear event.
11176      */
11177     removeAll : function(){
11178         this.data.clear();
11179         if(this.pruneModifiedRecords){
11180             this.modified = [];
11181         }
11182         this.fireEvent("clear", this);
11183     },
11184
11185     /**
11186      * Inserts Records to the Store at the given index and fires the add event.
11187      * @param {Number} index The start index at which to insert the passed Records.
11188      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11189      */
11190     insert : function(index, records){
11191         records = [].concat(records);
11192         for(var i = 0, len = records.length; i < len; i++){
11193             this.data.insert(index, records[i]);
11194             records[i].join(this);
11195         }
11196         this.fireEvent("add", this, records, index);
11197     },
11198
11199     /**
11200      * Get the index within the cache of the passed Record.
11201      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11202      * @return {Number} The index of the passed Record. Returns -1 if not found.
11203      */
11204     indexOf : function(record){
11205         return this.data.indexOf(record);
11206     },
11207
11208     /**
11209      * Get the index within the cache of the Record with the passed id.
11210      * @param {String} id The id of the Record to find.
11211      * @return {Number} The index of the Record. Returns -1 if not found.
11212      */
11213     indexOfId : function(id){
11214         return this.data.indexOfKey(id);
11215     },
11216
11217     /**
11218      * Get the Record with the specified id.
11219      * @param {String} id The id of the Record to find.
11220      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11221      */
11222     getById : function(id){
11223         return this.data.key(id);
11224     },
11225
11226     /**
11227      * Get the Record at the specified index.
11228      * @param {Number} index The index of the Record to find.
11229      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11230      */
11231     getAt : function(index){
11232         return this.data.itemAt(index);
11233     },
11234
11235     /**
11236      * Returns a range of Records between specified indices.
11237      * @param {Number} startIndex (optional) The starting index (defaults to 0)
11238      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11239      * @return {Roo.data.Record[]} An array of Records
11240      */
11241     getRange : function(start, end){
11242         return this.data.getRange(start, end);
11243     },
11244
11245     // private
11246     storeOptions : function(o){
11247         o = Roo.apply({}, o);
11248         delete o.callback;
11249         delete o.scope;
11250         this.lastOptions = o;
11251     },
11252
11253     /**
11254      * Loads the Record cache from the configured Proxy using the configured Reader.
11255      * <p>
11256      * If using remote paging, then the first load call must specify the <em>start</em>
11257      * and <em>limit</em> properties in the options.params property to establish the initial
11258      * position within the dataset, and the number of Records to cache on each read from the Proxy.
11259      * <p>
11260      * <strong>It is important to note that for remote data sources, loading is asynchronous,
11261      * and this call will return before the new data has been loaded. Perform any post-processing
11262      * in a callback function, or in a "load" event handler.</strong>
11263      * <p>
11264      * @param {Object} options An object containing properties which control loading options:<ul>
11265      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11266      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11267      * passed the following arguments:<ul>
11268      * <li>r : Roo.data.Record[]</li>
11269      * <li>options: Options object from the load call</li>
11270      * <li>success: Boolean success indicator</li></ul></li>
11271      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11272      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11273      * </ul>
11274      */
11275     load : function(options){
11276         options = options || {};
11277         if(this.fireEvent("beforeload", this, options) !== false){
11278             this.storeOptions(options);
11279             var p = Roo.apply(options.params || {}, this.baseParams);
11280             // if meta was not loaded from remote source.. try requesting it.
11281             if (!this.reader.metaFromRemote) {
11282                 p._requestMeta = 1;
11283             }
11284             if(this.sortInfo && this.remoteSort){
11285                 var pn = this.paramNames;
11286                 p[pn["sort"]] = this.sortInfo.field;
11287                 p[pn["dir"]] = this.sortInfo.direction;
11288             }
11289             if (this.multiSort) {
11290                 var pn = this.paramNames;
11291                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11292             }
11293             
11294             this.proxy.load(p, this.reader, this.loadRecords, this, options);
11295         }
11296     },
11297
11298     /**
11299      * Reloads the Record cache from the configured Proxy using the configured Reader and
11300      * the options from the last load operation performed.
11301      * @param {Object} options (optional) An object containing properties which may override the options
11302      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11303      * the most recently used options are reused).
11304      */
11305     reload : function(options){
11306         this.load(Roo.applyIf(options||{}, this.lastOptions));
11307     },
11308
11309     // private
11310     // Called as a callback by the Reader during a load operation.
11311     loadRecords : function(o, options, success){
11312         if(!o || success === false){
11313             if(success !== false){
11314                 this.fireEvent("load", this, [], options, o);
11315             }
11316             if(options.callback){
11317                 options.callback.call(options.scope || this, [], options, false);
11318             }
11319             return;
11320         }
11321         // if data returned failure - throw an exception.
11322         if (o.success === false) {
11323             // show a message if no listener is registered.
11324             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11325                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11326             }
11327             // loadmask wil be hooked into this..
11328             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11329             return;
11330         }
11331         var r = o.records, t = o.totalRecords || r.length;
11332         
11333         this.fireEvent("beforeloadadd", this, r, options, o);
11334         
11335         if(!options || options.add !== true){
11336             if(this.pruneModifiedRecords){
11337                 this.modified = [];
11338             }
11339             for(var i = 0, len = r.length; i < len; i++){
11340                 r[i].join(this);
11341             }
11342             if(this.snapshot){
11343                 this.data = this.snapshot;
11344                 delete this.snapshot;
11345             }
11346             this.data.clear();
11347             this.data.addAll(r);
11348             this.totalLength = t;
11349             this.applySort();
11350             this.fireEvent("datachanged", this);
11351         }else{
11352             this.totalLength = Math.max(t, this.data.length+r.length);
11353             this.add(r);
11354         }
11355         
11356         if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11357                 
11358             var e = new Roo.data.Record({});
11359
11360             e.set(this.parent.displayField, this.parent.emptyTitle);
11361             e.set(this.parent.valueField, '');
11362
11363             this.insert(0, e);
11364         }
11365             
11366         this.fireEvent("load", this, r, options, o);
11367         if(options.callback){
11368             options.callback.call(options.scope || this, r, options, true);
11369         }
11370     },
11371
11372
11373     /**
11374      * Loads data from a passed data block. A Reader which understands the format of the data
11375      * must have been configured in the constructor.
11376      * @param {Object} data The data block from which to read the Records.  The format of the data expected
11377      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11378      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11379      */
11380     loadData : function(o, append){
11381         var r = this.reader.readRecords(o);
11382         this.loadRecords(r, {add: append}, true);
11383     },
11384
11385     /**
11386      * Gets the number of cached records.
11387      * <p>
11388      * <em>If using paging, this may not be the total size of the dataset. If the data object
11389      * used by the Reader contains the dataset size, then the getTotalCount() function returns
11390      * the data set size</em>
11391      */
11392     getCount : function(){
11393         return this.data.length || 0;
11394     },
11395
11396     /**
11397      * Gets the total number of records in the dataset as returned by the server.
11398      * <p>
11399      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11400      * the dataset size</em>
11401      */
11402     getTotalCount : function(){
11403         return this.totalLength || 0;
11404     },
11405
11406     /**
11407      * Returns the sort state of the Store as an object with two properties:
11408      * <pre><code>
11409  field {String} The name of the field by which the Records are sorted
11410  direction {String} The sort order, "ASC" or "DESC"
11411      * </code></pre>
11412      */
11413     getSortState : function(){
11414         return this.sortInfo;
11415     },
11416
11417     // private
11418     applySort : function(){
11419         if(this.sortInfo && !this.remoteSort){
11420             var s = this.sortInfo, f = s.field;
11421             var st = this.fields.get(f).sortType;
11422             var fn = function(r1, r2){
11423                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11424                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11425             };
11426             this.data.sort(s.direction, fn);
11427             if(this.snapshot && this.snapshot != this.data){
11428                 this.snapshot.sort(s.direction, fn);
11429             }
11430         }
11431     },
11432
11433     /**
11434      * Sets the default sort column and order to be used by the next load operation.
11435      * @param {String} fieldName The name of the field to sort by.
11436      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11437      */
11438     setDefaultSort : function(field, dir){
11439         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11440     },
11441
11442     /**
11443      * Sort the Records.
11444      * If remote sorting is used, the sort is performed on the server, and the cache is
11445      * reloaded. If local sorting is used, the cache is sorted internally.
11446      * @param {String} fieldName The name of the field to sort by.
11447      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11448      */
11449     sort : function(fieldName, dir){
11450         var f = this.fields.get(fieldName);
11451         if(!dir){
11452             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11453             
11454             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11455                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11456             }else{
11457                 dir = f.sortDir;
11458             }
11459         }
11460         this.sortToggle[f.name] = dir;
11461         this.sortInfo = {field: f.name, direction: dir};
11462         if(!this.remoteSort){
11463             this.applySort();
11464             this.fireEvent("datachanged", this);
11465         }else{
11466             this.load(this.lastOptions);
11467         }
11468     },
11469
11470     /**
11471      * Calls the specified function for each of the Records in the cache.
11472      * @param {Function} fn The function to call. The Record is passed as the first parameter.
11473      * Returning <em>false</em> aborts and exits the iteration.
11474      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11475      */
11476     each : function(fn, scope){
11477         this.data.each(fn, scope);
11478     },
11479
11480     /**
11481      * Gets all records modified since the last commit.  Modified records are persisted across load operations
11482      * (e.g., during paging).
11483      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11484      */
11485     getModifiedRecords : function(){
11486         return this.modified;
11487     },
11488
11489     // private
11490     createFilterFn : function(property, value, anyMatch){
11491         if(!value.exec){ // not a regex
11492             value = String(value);
11493             if(value.length == 0){
11494                 return false;
11495             }
11496             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11497         }
11498         return function(r){
11499             return value.test(r.data[property]);
11500         };
11501     },
11502
11503     /**
11504      * Sums the value of <i>property</i> for each record between start and end and returns the result.
11505      * @param {String} property A field on your records
11506      * @param {Number} start The record index to start at (defaults to 0)
11507      * @param {Number} end The last record index to include (defaults to length - 1)
11508      * @return {Number} The sum
11509      */
11510     sum : function(property, start, end){
11511         var rs = this.data.items, v = 0;
11512         start = start || 0;
11513         end = (end || end === 0) ? end : rs.length-1;
11514
11515         for(var i = start; i <= end; i++){
11516             v += (rs[i].data[property] || 0);
11517         }
11518         return v;
11519     },
11520
11521     /**
11522      * Filter the records by a specified property.
11523      * @param {String} field A field on your records
11524      * @param {String/RegExp} value Either a string that the field
11525      * should start with or a RegExp to test against the field
11526      * @param {Boolean} anyMatch True to match any part not just the beginning
11527      */
11528     filter : function(property, value, anyMatch){
11529         var fn = this.createFilterFn(property, value, anyMatch);
11530         return fn ? this.filterBy(fn) : this.clearFilter();
11531     },
11532
11533     /**
11534      * Filter by a function. The specified function will be called with each
11535      * record in this data source. If the function returns true the record is included,
11536      * otherwise it is filtered.
11537      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11538      * @param {Object} scope (optional) The scope of the function (defaults to this)
11539      */
11540     filterBy : function(fn, scope){
11541         this.snapshot = this.snapshot || this.data;
11542         this.data = this.queryBy(fn, scope||this);
11543         this.fireEvent("datachanged", this);
11544     },
11545
11546     /**
11547      * Query the records by a specified property.
11548      * @param {String} field A field on your records
11549      * @param {String/RegExp} value Either a string that the field
11550      * should start with or a RegExp to test against the field
11551      * @param {Boolean} anyMatch True to match any part not just the beginning
11552      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11553      */
11554     query : function(property, value, anyMatch){
11555         var fn = this.createFilterFn(property, value, anyMatch);
11556         return fn ? this.queryBy(fn) : this.data.clone();
11557     },
11558
11559     /**
11560      * Query by a function. The specified function will be called with each
11561      * record in this data source. If the function returns true the record is included
11562      * in the results.
11563      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11564      * @param {Object} scope (optional) The scope of the function (defaults to this)
11565       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11566      **/
11567     queryBy : function(fn, scope){
11568         var data = this.snapshot || this.data;
11569         return data.filterBy(fn, scope||this);
11570     },
11571
11572     /**
11573      * Collects unique values for a particular dataIndex from this store.
11574      * @param {String} dataIndex The property to collect
11575      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11576      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11577      * @return {Array} An array of the unique values
11578      **/
11579     collect : function(dataIndex, allowNull, bypassFilter){
11580         var d = (bypassFilter === true && this.snapshot) ?
11581                 this.snapshot.items : this.data.items;
11582         var v, sv, r = [], l = {};
11583         for(var i = 0, len = d.length; i < len; i++){
11584             v = d[i].data[dataIndex];
11585             sv = String(v);
11586             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11587                 l[sv] = true;
11588                 r[r.length] = v;
11589             }
11590         }
11591         return r;
11592     },
11593
11594     /**
11595      * Revert to a view of the Record cache with no filtering applied.
11596      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11597      */
11598     clearFilter : function(suppressEvent){
11599         if(this.snapshot && this.snapshot != this.data){
11600             this.data = this.snapshot;
11601             delete this.snapshot;
11602             if(suppressEvent !== true){
11603                 this.fireEvent("datachanged", this);
11604             }
11605         }
11606     },
11607
11608     // private
11609     afterEdit : function(record){
11610         if(this.modified.indexOf(record) == -1){
11611             this.modified.push(record);
11612         }
11613         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11614     },
11615     
11616     // private
11617     afterReject : function(record){
11618         this.modified.remove(record);
11619         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11620     },
11621
11622     // private
11623     afterCommit : function(record){
11624         this.modified.remove(record);
11625         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11626     },
11627
11628     /**
11629      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11630      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11631      */
11632     commitChanges : function(){
11633         var m = this.modified.slice(0);
11634         this.modified = [];
11635         for(var i = 0, len = m.length; i < len; i++){
11636             m[i].commit();
11637         }
11638     },
11639
11640     /**
11641      * Cancel outstanding changes on all changed records.
11642      */
11643     rejectChanges : function(){
11644         var m = this.modified.slice(0);
11645         this.modified = [];
11646         for(var i = 0, len = m.length; i < len; i++){
11647             m[i].reject();
11648         }
11649     },
11650
11651     onMetaChange : function(meta, rtype, o){
11652         this.recordType = rtype;
11653         this.fields = rtype.prototype.fields;
11654         delete this.snapshot;
11655         this.sortInfo = meta.sortInfo || this.sortInfo;
11656         this.modified = [];
11657         this.fireEvent('metachange', this, this.reader.meta);
11658     },
11659     
11660     moveIndex : function(data, type)
11661     {
11662         var index = this.indexOf(data);
11663         
11664         var newIndex = index + type;
11665         
11666         this.remove(data);
11667         
11668         this.insert(newIndex, data);
11669         
11670     }
11671 });/*
11672  * Based on:
11673  * Ext JS Library 1.1.1
11674  * Copyright(c) 2006-2007, Ext JS, LLC.
11675  *
11676  * Originally Released Under LGPL - original licence link has changed is not relivant.
11677  *
11678  * Fork - LGPL
11679  * <script type="text/javascript">
11680  */
11681
11682 /**
11683  * @class Roo.data.SimpleStore
11684  * @extends Roo.data.Store
11685  * Small helper class to make creating Stores from Array data easier.
11686  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11687  * @cfg {Array} fields An array of field definition objects, or field name strings.
11688  * @cfg {Array} data The multi-dimensional array of data
11689  * @constructor
11690  * @param {Object} config
11691  */
11692 Roo.data.SimpleStore = function(config){
11693     Roo.data.SimpleStore.superclass.constructor.call(this, {
11694         isLocal : true,
11695         reader: new Roo.data.ArrayReader({
11696                 id: config.id
11697             },
11698             Roo.data.Record.create(config.fields)
11699         ),
11700         proxy : new Roo.data.MemoryProxy(config.data)
11701     });
11702     this.load();
11703 };
11704 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11705  * Based on:
11706  * Ext JS Library 1.1.1
11707  * Copyright(c) 2006-2007, Ext JS, LLC.
11708  *
11709  * Originally Released Under LGPL - original licence link has changed is not relivant.
11710  *
11711  * Fork - LGPL
11712  * <script type="text/javascript">
11713  */
11714
11715 /**
11716 /**
11717  * @extends Roo.data.Store
11718  * @class Roo.data.JsonStore
11719  * Small helper class to make creating Stores for JSON data easier. <br/>
11720 <pre><code>
11721 var store = new Roo.data.JsonStore({
11722     url: 'get-images.php',
11723     root: 'images',
11724     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11725 });
11726 </code></pre>
11727  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11728  * JsonReader and HttpProxy (unless inline data is provided).</b>
11729  * @cfg {Array} fields An array of field definition objects, or field name strings.
11730  * @constructor
11731  * @param {Object} config
11732  */
11733 Roo.data.JsonStore = function(c){
11734     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11735         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11736         reader: new Roo.data.JsonReader(c, c.fields)
11737     }));
11738 };
11739 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11740  * Based on:
11741  * Ext JS Library 1.1.1
11742  * Copyright(c) 2006-2007, Ext JS, LLC.
11743  *
11744  * Originally Released Under LGPL - original licence link has changed is not relivant.
11745  *
11746  * Fork - LGPL
11747  * <script type="text/javascript">
11748  */
11749
11750  
11751 Roo.data.Field = function(config){
11752     if(typeof config == "string"){
11753         config = {name: config};
11754     }
11755     Roo.apply(this, config);
11756     
11757     if(!this.type){
11758         this.type = "auto";
11759     }
11760     
11761     var st = Roo.data.SortTypes;
11762     // named sortTypes are supported, here we look them up
11763     if(typeof this.sortType == "string"){
11764         this.sortType = st[this.sortType];
11765     }
11766     
11767     // set default sortType for strings and dates
11768     if(!this.sortType){
11769         switch(this.type){
11770             case "string":
11771                 this.sortType = st.asUCString;
11772                 break;
11773             case "date":
11774                 this.sortType = st.asDate;
11775                 break;
11776             default:
11777                 this.sortType = st.none;
11778         }
11779     }
11780
11781     // define once
11782     var stripRe = /[\$,%]/g;
11783
11784     // prebuilt conversion function for this field, instead of
11785     // switching every time we're reading a value
11786     if(!this.convert){
11787         var cv, dateFormat = this.dateFormat;
11788         switch(this.type){
11789             case "":
11790             case "auto":
11791             case undefined:
11792                 cv = function(v){ return v; };
11793                 break;
11794             case "string":
11795                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11796                 break;
11797             case "int":
11798                 cv = function(v){
11799                     return v !== undefined && v !== null && v !== '' ?
11800                            parseInt(String(v).replace(stripRe, ""), 10) : '';
11801                     };
11802                 break;
11803             case "float":
11804                 cv = function(v){
11805                     return v !== undefined && v !== null && v !== '' ?
11806                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
11807                     };
11808                 break;
11809             case "bool":
11810             case "boolean":
11811                 cv = function(v){ return v === true || v === "true" || v == 1; };
11812                 break;
11813             case "date":
11814                 cv = function(v){
11815                     if(!v){
11816                         return '';
11817                     }
11818                     if(v instanceof Date){
11819                         return v;
11820                     }
11821                     if(dateFormat){
11822                         if(dateFormat == "timestamp"){
11823                             return new Date(v*1000);
11824                         }
11825                         return Date.parseDate(v, dateFormat);
11826                     }
11827                     var parsed = Date.parse(v);
11828                     return parsed ? new Date(parsed) : null;
11829                 };
11830              break;
11831             
11832         }
11833         this.convert = cv;
11834     }
11835 };
11836
11837 Roo.data.Field.prototype = {
11838     dateFormat: null,
11839     defaultValue: "",
11840     mapping: null,
11841     sortType : null,
11842     sortDir : "ASC"
11843 };/*
11844  * Based on:
11845  * Ext JS Library 1.1.1
11846  * Copyright(c) 2006-2007, Ext JS, LLC.
11847  *
11848  * Originally Released Under LGPL - original licence link has changed is not relivant.
11849  *
11850  * Fork - LGPL
11851  * <script type="text/javascript">
11852  */
11853  
11854 // Base class for reading structured data from a data source.  This class is intended to be
11855 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11856
11857 /**
11858  * @class Roo.data.DataReader
11859  * Base class for reading structured data from a data source.  This class is intended to be
11860  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11861  */
11862
11863 Roo.data.DataReader = function(meta, recordType){
11864     
11865     this.meta = meta;
11866     
11867     this.recordType = recordType instanceof Array ? 
11868         Roo.data.Record.create(recordType) : recordType;
11869 };
11870
11871 Roo.data.DataReader.prototype = {
11872      /**
11873      * Create an empty record
11874      * @param {Object} data (optional) - overlay some values
11875      * @return {Roo.data.Record} record created.
11876      */
11877     newRow :  function(d) {
11878         var da =  {};
11879         this.recordType.prototype.fields.each(function(c) {
11880             switch( c.type) {
11881                 case 'int' : da[c.name] = 0; break;
11882                 case 'date' : da[c.name] = new Date(); break;
11883                 case 'float' : da[c.name] = 0.0; break;
11884                 case 'boolean' : da[c.name] = false; break;
11885                 default : da[c.name] = ""; break;
11886             }
11887             
11888         });
11889         return new this.recordType(Roo.apply(da, d));
11890     }
11891     
11892 };/*
11893  * Based on:
11894  * Ext JS Library 1.1.1
11895  * Copyright(c) 2006-2007, Ext JS, LLC.
11896  *
11897  * Originally Released Under LGPL - original licence link has changed is not relivant.
11898  *
11899  * Fork - LGPL
11900  * <script type="text/javascript">
11901  */
11902
11903 /**
11904  * @class Roo.data.DataProxy
11905  * @extends Roo.data.Observable
11906  * This class is an abstract base class for implementations which provide retrieval of
11907  * unformatted data objects.<br>
11908  * <p>
11909  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11910  * (of the appropriate type which knows how to parse the data object) to provide a block of
11911  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11912  * <p>
11913  * Custom implementations must implement the load method as described in
11914  * {@link Roo.data.HttpProxy#load}.
11915  */
11916 Roo.data.DataProxy = function(){
11917     this.addEvents({
11918         /**
11919          * @event beforeload
11920          * Fires before a network request is made to retrieve a data object.
11921          * @param {Object} This DataProxy object.
11922          * @param {Object} params The params parameter to the load function.
11923          */
11924         beforeload : true,
11925         /**
11926          * @event load
11927          * Fires before the load method's callback is called.
11928          * @param {Object} This DataProxy object.
11929          * @param {Object} o The data object.
11930          * @param {Object} arg The callback argument object passed to the load function.
11931          */
11932         load : true,
11933         /**
11934          * @event loadexception
11935          * Fires if an Exception occurs during data retrieval.
11936          * @param {Object} This DataProxy object.
11937          * @param {Object} o The data object.
11938          * @param {Object} arg The callback argument object passed to the load function.
11939          * @param {Object} e The Exception.
11940          */
11941         loadexception : true
11942     });
11943     Roo.data.DataProxy.superclass.constructor.call(this);
11944 };
11945
11946 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11947
11948     /**
11949      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11950      */
11951 /*
11952  * Based on:
11953  * Ext JS Library 1.1.1
11954  * Copyright(c) 2006-2007, Ext JS, LLC.
11955  *
11956  * Originally Released Under LGPL - original licence link has changed is not relivant.
11957  *
11958  * Fork - LGPL
11959  * <script type="text/javascript">
11960  */
11961 /**
11962  * @class Roo.data.MemoryProxy
11963  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11964  * to the Reader when its load method is called.
11965  * @constructor
11966  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11967  */
11968 Roo.data.MemoryProxy = function(data){
11969     if (data.data) {
11970         data = data.data;
11971     }
11972     Roo.data.MemoryProxy.superclass.constructor.call(this);
11973     this.data = data;
11974 };
11975
11976 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11977     
11978     /**
11979      * Load data from the requested source (in this case an in-memory
11980      * data object passed to the constructor), read the data object into
11981      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11982      * process that block using the passed callback.
11983      * @param {Object} params This parameter is not used by the MemoryProxy class.
11984      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11985      * object into a block of Roo.data.Records.
11986      * @param {Function} callback The function into which to pass the block of Roo.data.records.
11987      * The function must be passed <ul>
11988      * <li>The Record block object</li>
11989      * <li>The "arg" argument from the load function</li>
11990      * <li>A boolean success indicator</li>
11991      * </ul>
11992      * @param {Object} scope The scope in which to call the callback
11993      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11994      */
11995     load : function(params, reader, callback, scope, arg){
11996         params = params || {};
11997         var result;
11998         try {
11999             result = reader.readRecords(this.data);
12000         }catch(e){
12001             this.fireEvent("loadexception", this, arg, null, e);
12002             callback.call(scope, null, arg, false);
12003             return;
12004         }
12005         callback.call(scope, result, arg, true);
12006     },
12007     
12008     // private
12009     update : function(params, records){
12010         
12011     }
12012 });/*
12013  * Based on:
12014  * Ext JS Library 1.1.1
12015  * Copyright(c) 2006-2007, Ext JS, LLC.
12016  *
12017  * Originally Released Under LGPL - original licence link has changed is not relivant.
12018  *
12019  * Fork - LGPL
12020  * <script type="text/javascript">
12021  */
12022 /**
12023  * @class Roo.data.HttpProxy
12024  * @extends Roo.data.DataProxy
12025  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12026  * configured to reference a certain URL.<br><br>
12027  * <p>
12028  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12029  * from which the running page was served.<br><br>
12030  * <p>
12031  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12032  * <p>
12033  * Be aware that to enable the browser to parse an XML document, the server must set
12034  * the Content-Type header in the HTTP response to "text/xml".
12035  * @constructor
12036  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12037  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
12038  * will be used to make the request.
12039  */
12040 Roo.data.HttpProxy = function(conn){
12041     Roo.data.HttpProxy.superclass.constructor.call(this);
12042     // is conn a conn config or a real conn?
12043     this.conn = conn;
12044     this.useAjax = !conn || !conn.events;
12045   
12046 };
12047
12048 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12049     // thse are take from connection...
12050     
12051     /**
12052      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12053      */
12054     /**
12055      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12056      * extra parameters to each request made by this object. (defaults to undefined)
12057      */
12058     /**
12059      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12060      *  to each request made by this object. (defaults to undefined)
12061      */
12062     /**
12063      * @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)
12064      */
12065     /**
12066      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12067      */
12068      /**
12069      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12070      * @type Boolean
12071      */
12072   
12073
12074     /**
12075      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12076      * @type Boolean
12077      */
12078     /**
12079      * Return the {@link Roo.data.Connection} object being used by this Proxy.
12080      * @return {Connection} The Connection object. This object may be used to subscribe to events on
12081      * a finer-grained basis than the DataProxy events.
12082      */
12083     getConnection : function(){
12084         return this.useAjax ? Roo.Ajax : this.conn;
12085     },
12086
12087     /**
12088      * Load data from the configured {@link Roo.data.Connection}, read the data object into
12089      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12090      * process that block using the passed callback.
12091      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12092      * for the request to the remote server.
12093      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12094      * object into a block of Roo.data.Records.
12095      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12096      * The function must be passed <ul>
12097      * <li>The Record block object</li>
12098      * <li>The "arg" argument from the load function</li>
12099      * <li>A boolean success indicator</li>
12100      * </ul>
12101      * @param {Object} scope The scope in which to call the callback
12102      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12103      */
12104     load : function(params, reader, callback, scope, arg){
12105         if(this.fireEvent("beforeload", this, params) !== false){
12106             var  o = {
12107                 params : params || {},
12108                 request: {
12109                     callback : callback,
12110                     scope : scope,
12111                     arg : arg
12112                 },
12113                 reader: reader,
12114                 callback : this.loadResponse,
12115                 scope: this
12116             };
12117             if(this.useAjax){
12118                 Roo.applyIf(o, this.conn);
12119                 if(this.activeRequest){
12120                     Roo.Ajax.abort(this.activeRequest);
12121                 }
12122                 this.activeRequest = Roo.Ajax.request(o);
12123             }else{
12124                 this.conn.request(o);
12125             }
12126         }else{
12127             callback.call(scope||this, null, arg, false);
12128         }
12129     },
12130
12131     // private
12132     loadResponse : function(o, success, response){
12133         delete this.activeRequest;
12134         if(!success){
12135             this.fireEvent("loadexception", this, o, response);
12136             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12137             return;
12138         }
12139         var result;
12140         try {
12141             result = o.reader.read(response);
12142         }catch(e){
12143             this.fireEvent("loadexception", this, o, response, e);
12144             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12145             return;
12146         }
12147         
12148         this.fireEvent("load", this, o, o.request.arg);
12149         o.request.callback.call(o.request.scope, result, o.request.arg, true);
12150     },
12151
12152     // private
12153     update : function(dataSet){
12154
12155     },
12156
12157     // private
12158     updateResponse : function(dataSet){
12159
12160     }
12161 });/*
12162  * Based on:
12163  * Ext JS Library 1.1.1
12164  * Copyright(c) 2006-2007, Ext JS, LLC.
12165  *
12166  * Originally Released Under LGPL - original licence link has changed is not relivant.
12167  *
12168  * Fork - LGPL
12169  * <script type="text/javascript">
12170  */
12171
12172 /**
12173  * @class Roo.data.ScriptTagProxy
12174  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12175  * other than the originating domain of the running page.<br><br>
12176  * <p>
12177  * <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
12178  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12179  * <p>
12180  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12181  * source code that is used as the source inside a &lt;script> tag.<br><br>
12182  * <p>
12183  * In order for the browser to process the returned data, the server must wrap the data object
12184  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12185  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12186  * depending on whether the callback name was passed:
12187  * <p>
12188  * <pre><code>
12189 boolean scriptTag = false;
12190 String cb = request.getParameter("callback");
12191 if (cb != null) {
12192     scriptTag = true;
12193     response.setContentType("text/javascript");
12194 } else {
12195     response.setContentType("application/x-json");
12196 }
12197 Writer out = response.getWriter();
12198 if (scriptTag) {
12199     out.write(cb + "(");
12200 }
12201 out.print(dataBlock.toJsonString());
12202 if (scriptTag) {
12203     out.write(");");
12204 }
12205 </pre></code>
12206  *
12207  * @constructor
12208  * @param {Object} config A configuration object.
12209  */
12210 Roo.data.ScriptTagProxy = function(config){
12211     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12212     Roo.apply(this, config);
12213     this.head = document.getElementsByTagName("head")[0];
12214 };
12215
12216 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12217
12218 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12219     /**
12220      * @cfg {String} url The URL from which to request the data object.
12221      */
12222     /**
12223      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12224      */
12225     timeout : 30000,
12226     /**
12227      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12228      * the server the name of the callback function set up by the load call to process the returned data object.
12229      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12230      * javascript output which calls this named function passing the data object as its only parameter.
12231      */
12232     callbackParam : "callback",
12233     /**
12234      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12235      * name to the request.
12236      */
12237     nocache : true,
12238
12239     /**
12240      * Load data from the configured URL, read the data object into
12241      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12242      * process that block using the passed callback.
12243      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12244      * for the request to the remote server.
12245      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12246      * object into a block of Roo.data.Records.
12247      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12248      * The function must be passed <ul>
12249      * <li>The Record block object</li>
12250      * <li>The "arg" argument from the load function</li>
12251      * <li>A boolean success indicator</li>
12252      * </ul>
12253      * @param {Object} scope The scope in which to call the callback
12254      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12255      */
12256     load : function(params, reader, callback, scope, arg){
12257         if(this.fireEvent("beforeload", this, params) !== false){
12258
12259             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12260
12261             var url = this.url;
12262             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12263             if(this.nocache){
12264                 url += "&_dc=" + (new Date().getTime());
12265             }
12266             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12267             var trans = {
12268                 id : transId,
12269                 cb : "stcCallback"+transId,
12270                 scriptId : "stcScript"+transId,
12271                 params : params,
12272                 arg : arg,
12273                 url : url,
12274                 callback : callback,
12275                 scope : scope,
12276                 reader : reader
12277             };
12278             var conn = this;
12279
12280             window[trans.cb] = function(o){
12281                 conn.handleResponse(o, trans);
12282             };
12283
12284             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12285
12286             if(this.autoAbort !== false){
12287                 this.abort();
12288             }
12289
12290             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12291
12292             var script = document.createElement("script");
12293             script.setAttribute("src", url);
12294             script.setAttribute("type", "text/javascript");
12295             script.setAttribute("id", trans.scriptId);
12296             this.head.appendChild(script);
12297
12298             this.trans = trans;
12299         }else{
12300             callback.call(scope||this, null, arg, false);
12301         }
12302     },
12303
12304     // private
12305     isLoading : function(){
12306         return this.trans ? true : false;
12307     },
12308
12309     /**
12310      * Abort the current server request.
12311      */
12312     abort : function(){
12313         if(this.isLoading()){
12314             this.destroyTrans(this.trans);
12315         }
12316     },
12317
12318     // private
12319     destroyTrans : function(trans, isLoaded){
12320         this.head.removeChild(document.getElementById(trans.scriptId));
12321         clearTimeout(trans.timeoutId);
12322         if(isLoaded){
12323             window[trans.cb] = undefined;
12324             try{
12325                 delete window[trans.cb];
12326             }catch(e){}
12327         }else{
12328             // if hasn't been loaded, wait for load to remove it to prevent script error
12329             window[trans.cb] = function(){
12330                 window[trans.cb] = undefined;
12331                 try{
12332                     delete window[trans.cb];
12333                 }catch(e){}
12334             };
12335         }
12336     },
12337
12338     // private
12339     handleResponse : function(o, trans){
12340         this.trans = false;
12341         this.destroyTrans(trans, true);
12342         var result;
12343         try {
12344             result = trans.reader.readRecords(o);
12345         }catch(e){
12346             this.fireEvent("loadexception", this, o, trans.arg, e);
12347             trans.callback.call(trans.scope||window, null, trans.arg, false);
12348             return;
12349         }
12350         this.fireEvent("load", this, o, trans.arg);
12351         trans.callback.call(trans.scope||window, result, trans.arg, true);
12352     },
12353
12354     // private
12355     handleFailure : function(trans){
12356         this.trans = false;
12357         this.destroyTrans(trans, false);
12358         this.fireEvent("loadexception", this, null, trans.arg);
12359         trans.callback.call(trans.scope||window, null, trans.arg, false);
12360     }
12361 });/*
12362  * Based on:
12363  * Ext JS Library 1.1.1
12364  * Copyright(c) 2006-2007, Ext JS, LLC.
12365  *
12366  * Originally Released Under LGPL - original licence link has changed is not relivant.
12367  *
12368  * Fork - LGPL
12369  * <script type="text/javascript">
12370  */
12371
12372 /**
12373  * @class Roo.data.JsonReader
12374  * @extends Roo.data.DataReader
12375  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12376  * based on mappings in a provided Roo.data.Record constructor.
12377  * 
12378  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12379  * in the reply previously. 
12380  * 
12381  * <p>
12382  * Example code:
12383  * <pre><code>
12384 var RecordDef = Roo.data.Record.create([
12385     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
12386     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
12387 ]);
12388 var myReader = new Roo.data.JsonReader({
12389     totalProperty: "results",    // The property which contains the total dataset size (optional)
12390     root: "rows",                // The property which contains an Array of row objects
12391     id: "id"                     // The property within each row object that provides an ID for the record (optional)
12392 }, RecordDef);
12393 </code></pre>
12394  * <p>
12395  * This would consume a JSON file like this:
12396  * <pre><code>
12397 { 'results': 2, 'rows': [
12398     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12399     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12400 }
12401 </code></pre>
12402  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12403  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12404  * paged from the remote server.
12405  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12406  * @cfg {String} root name of the property which contains the Array of row objects.
12407  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12408  * @cfg {Array} fields Array of field definition objects
12409  * @constructor
12410  * Create a new JsonReader
12411  * @param {Object} meta Metadata configuration options
12412  * @param {Object} recordType Either an Array of field definition objects,
12413  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12414  */
12415 Roo.data.JsonReader = function(meta, recordType){
12416     
12417     meta = meta || {};
12418     // set some defaults:
12419     Roo.applyIf(meta, {
12420         totalProperty: 'total',
12421         successProperty : 'success',
12422         root : 'data',
12423         id : 'id'
12424     });
12425     
12426     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12427 };
12428 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12429     
12430     /**
12431      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
12432      * Used by Store query builder to append _requestMeta to params.
12433      * 
12434      */
12435     metaFromRemote : false,
12436     /**
12437      * This method is only used by a DataProxy which has retrieved data from a remote server.
12438      * @param {Object} response The XHR object which contains the JSON data in its responseText.
12439      * @return {Object} data A data block which is used by an Roo.data.Store object as
12440      * a cache of Roo.data.Records.
12441      */
12442     read : function(response){
12443         var json = response.responseText;
12444        
12445         var o = /* eval:var:o */ eval("("+json+")");
12446         if(!o) {
12447             throw {message: "JsonReader.read: Json object not found"};
12448         }
12449         
12450         if(o.metaData){
12451             
12452             delete this.ef;
12453             this.metaFromRemote = true;
12454             this.meta = o.metaData;
12455             this.recordType = Roo.data.Record.create(o.metaData.fields);
12456             this.onMetaChange(this.meta, this.recordType, o);
12457         }
12458         return this.readRecords(o);
12459     },
12460
12461     // private function a store will implement
12462     onMetaChange : function(meta, recordType, o){
12463
12464     },
12465
12466     /**
12467          * @ignore
12468          */
12469     simpleAccess: function(obj, subsc) {
12470         return obj[subsc];
12471     },
12472
12473         /**
12474          * @ignore
12475          */
12476     getJsonAccessor: function(){
12477         var re = /[\[\.]/;
12478         return function(expr) {
12479             try {
12480                 return(re.test(expr))
12481                     ? new Function("obj", "return obj." + expr)
12482                     : function(obj){
12483                         return obj[expr];
12484                     };
12485             } catch(e){}
12486             return Roo.emptyFn;
12487         };
12488     }(),
12489
12490     /**
12491      * Create a data block containing Roo.data.Records from an XML document.
12492      * @param {Object} o An object which contains an Array of row objects in the property specified
12493      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12494      * which contains the total size of the dataset.
12495      * @return {Object} data A data block which is used by an Roo.data.Store object as
12496      * a cache of Roo.data.Records.
12497      */
12498     readRecords : function(o){
12499         /**
12500          * After any data loads, the raw JSON data is available for further custom processing.
12501          * @type Object
12502          */
12503         this.o = o;
12504         var s = this.meta, Record = this.recordType,
12505             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12506
12507 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
12508         if (!this.ef) {
12509             if(s.totalProperty) {
12510                     this.getTotal = this.getJsonAccessor(s.totalProperty);
12511                 }
12512                 if(s.successProperty) {
12513                     this.getSuccess = this.getJsonAccessor(s.successProperty);
12514                 }
12515                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12516                 if (s.id) {
12517                         var g = this.getJsonAccessor(s.id);
12518                         this.getId = function(rec) {
12519                                 var r = g(rec);  
12520                                 return (r === undefined || r === "") ? null : r;
12521                         };
12522                 } else {
12523                         this.getId = function(){return null;};
12524                 }
12525             this.ef = [];
12526             for(var jj = 0; jj < fl; jj++){
12527                 f = fi[jj];
12528                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12529                 this.ef[jj] = this.getJsonAccessor(map);
12530             }
12531         }
12532
12533         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12534         if(s.totalProperty){
12535             var vt = parseInt(this.getTotal(o), 10);
12536             if(!isNaN(vt)){
12537                 totalRecords = vt;
12538             }
12539         }
12540         if(s.successProperty){
12541             var vs = this.getSuccess(o);
12542             if(vs === false || vs === 'false'){
12543                 success = false;
12544             }
12545         }
12546         var records = [];
12547         for(var i = 0; i < c; i++){
12548                 var n = root[i];
12549             var values = {};
12550             var id = this.getId(n);
12551             for(var j = 0; j < fl; j++){
12552                 f = fi[j];
12553             var v = this.ef[j](n);
12554             if (!f.convert) {
12555                 Roo.log('missing convert for ' + f.name);
12556                 Roo.log(f);
12557                 continue;
12558             }
12559             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12560             }
12561             var record = new Record(values, id);
12562             record.json = n;
12563             records[i] = record;
12564         }
12565         return {
12566             raw : o,
12567             success : success,
12568             records : records,
12569             totalRecords : totalRecords
12570         };
12571     }
12572 });/*
12573  * Based on:
12574  * Ext JS Library 1.1.1
12575  * Copyright(c) 2006-2007, Ext JS, LLC.
12576  *
12577  * Originally Released Under LGPL - original licence link has changed is not relivant.
12578  *
12579  * Fork - LGPL
12580  * <script type="text/javascript">
12581  */
12582
12583 /**
12584  * @class Roo.data.ArrayReader
12585  * @extends Roo.data.DataReader
12586  * Data reader class to create an Array of Roo.data.Record objects from an Array.
12587  * Each element of that Array represents a row of data fields. The
12588  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12589  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12590  * <p>
12591  * Example code:.
12592  * <pre><code>
12593 var RecordDef = Roo.data.Record.create([
12594     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
12595     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
12596 ]);
12597 var myReader = new Roo.data.ArrayReader({
12598     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
12599 }, RecordDef);
12600 </code></pre>
12601  * <p>
12602  * This would consume an Array like this:
12603  * <pre><code>
12604 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12605   </code></pre>
12606  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12607  * @constructor
12608  * Create a new JsonReader
12609  * @param {Object} meta Metadata configuration options.
12610  * @param {Object} recordType Either an Array of field definition objects
12611  * as specified to {@link Roo.data.Record#create},
12612  * or an {@link Roo.data.Record} object
12613  * created using {@link Roo.data.Record#create}.
12614  */
12615 Roo.data.ArrayReader = function(meta, recordType){
12616     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12617 };
12618
12619 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12620     /**
12621      * Create a data block containing Roo.data.Records from an XML document.
12622      * @param {Object} o An Array of row objects which represents the dataset.
12623      * @return {Object} data A data block which is used by an Roo.data.Store object as
12624      * a cache of Roo.data.Records.
12625      */
12626     readRecords : function(o){
12627         var sid = this.meta ? this.meta.id : null;
12628         var recordType = this.recordType, fields = recordType.prototype.fields;
12629         var records = [];
12630         var root = o;
12631             for(var i = 0; i < root.length; i++){
12632                     var n = root[i];
12633                 var values = {};
12634                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12635                 for(var j = 0, jlen = fields.length; j < jlen; j++){
12636                 var f = fields.items[j];
12637                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12638                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12639                 v = f.convert(v);
12640                 values[f.name] = v;
12641             }
12642                 var record = new recordType(values, id);
12643                 record.json = n;
12644                 records[records.length] = record;
12645             }
12646             return {
12647                 records : records,
12648                 totalRecords : records.length
12649             };
12650     }
12651 });/*
12652  * - LGPL
12653  * * 
12654  */
12655
12656 /**
12657  * @class Roo.bootstrap.ComboBox
12658  * @extends Roo.bootstrap.TriggerField
12659  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12660  * @cfg {Boolean} append (true|false) default false
12661  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12662  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12663  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12664  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12665  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12666  * @cfg {Boolean} animate default true
12667  * @cfg {Boolean} emptyResultText only for touch device
12668  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12669  * @cfg {String} emptyTitle default ''
12670  * @constructor
12671  * Create a new ComboBox.
12672  * @param {Object} config Configuration options
12673  */
12674 Roo.bootstrap.ComboBox = function(config){
12675     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12676     this.addEvents({
12677         /**
12678          * @event expand
12679          * Fires when the dropdown list is expanded
12680         * @param {Roo.bootstrap.ComboBox} combo This combo box
12681         */
12682         'expand' : true,
12683         /**
12684          * @event collapse
12685          * Fires when the dropdown list is collapsed
12686         * @param {Roo.bootstrap.ComboBox} combo This combo box
12687         */
12688         'collapse' : true,
12689         /**
12690          * @event beforeselect
12691          * Fires before a list item is selected. Return false to cancel the selection.
12692         * @param {Roo.bootstrap.ComboBox} combo This combo box
12693         * @param {Roo.data.Record} record The data record returned from the underlying store
12694         * @param {Number} index The index of the selected item in the dropdown list
12695         */
12696         'beforeselect' : true,
12697         /**
12698          * @event select
12699          * Fires when a list item is selected
12700         * @param {Roo.bootstrap.ComboBox} combo This combo box
12701         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12702         * @param {Number} index The index of the selected item in the dropdown list
12703         */
12704         'select' : true,
12705         /**
12706          * @event beforequery
12707          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12708          * The event object passed has these properties:
12709         * @param {Roo.bootstrap.ComboBox} combo This combo box
12710         * @param {String} query The query
12711         * @param {Boolean} forceAll true to force "all" query
12712         * @param {Boolean} cancel true to cancel the query
12713         * @param {Object} e The query event object
12714         */
12715         'beforequery': true,
12716          /**
12717          * @event add
12718          * Fires when the 'add' icon is pressed (add a listener to enable add button)
12719         * @param {Roo.bootstrap.ComboBox} combo This combo box
12720         */
12721         'add' : true,
12722         /**
12723          * @event edit
12724          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12725         * @param {Roo.bootstrap.ComboBox} combo This combo box
12726         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12727         */
12728         'edit' : true,
12729         /**
12730          * @event remove
12731          * Fires when the remove value from the combobox array
12732         * @param {Roo.bootstrap.ComboBox} combo This combo box
12733         */
12734         'remove' : true,
12735         /**
12736          * @event afterremove
12737          * Fires when the remove value from the combobox array
12738         * @param {Roo.bootstrap.ComboBox} combo This combo box
12739         */
12740         'afterremove' : true,
12741         /**
12742          * @event specialfilter
12743          * Fires when specialfilter
12744             * @param {Roo.bootstrap.ComboBox} combo This combo box
12745             */
12746         'specialfilter' : true,
12747         /**
12748          * @event tick
12749          * Fires when tick the element
12750             * @param {Roo.bootstrap.ComboBox} combo This combo box
12751             */
12752         'tick' : true,
12753         /**
12754          * @event touchviewdisplay
12755          * Fires when touch view require special display (default is using displayField)
12756             * @param {Roo.bootstrap.ComboBox} combo This combo box
12757             * @param {Object} cfg set html .
12758             */
12759         'touchviewdisplay' : true
12760         
12761     });
12762     
12763     this.item = [];
12764     this.tickItems = [];
12765     
12766     this.selectedIndex = -1;
12767     if(this.mode == 'local'){
12768         if(config.queryDelay === undefined){
12769             this.queryDelay = 10;
12770         }
12771         if(config.minChars === undefined){
12772             this.minChars = 0;
12773         }
12774     }
12775 };
12776
12777 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12778      
12779     /**
12780      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12781      * rendering into an Roo.Editor, defaults to false)
12782      */
12783     /**
12784      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12785      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12786      */
12787     /**
12788      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12789      */
12790     /**
12791      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12792      * the dropdown list (defaults to undefined, with no header element)
12793      */
12794
12795      /**
12796      * @cfg {String/Roo.Template} tpl The template to use to render the output
12797      */
12798      
12799      /**
12800      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12801      */
12802     listWidth: undefined,
12803     /**
12804      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12805      * mode = 'remote' or 'text' if mode = 'local')
12806      */
12807     displayField: undefined,
12808     
12809     /**
12810      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12811      * mode = 'remote' or 'value' if mode = 'local'). 
12812      * Note: use of a valueField requires the user make a selection
12813      * in order for a value to be mapped.
12814      */
12815     valueField: undefined,
12816     /**
12817      * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12818      */
12819     modalTitle : '',
12820     
12821     /**
12822      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12823      * field's data value (defaults to the underlying DOM element's name)
12824      */
12825     hiddenName: undefined,
12826     /**
12827      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12828      */
12829     listClass: '',
12830     /**
12831      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12832      */
12833     selectedClass: 'active',
12834     
12835     /**
12836      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12837      */
12838     shadow:'sides',
12839     /**
12840      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12841      * anchor positions (defaults to 'tl-bl')
12842      */
12843     listAlign: 'tl-bl?',
12844     /**
12845      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12846      */
12847     maxHeight: 300,
12848     /**
12849      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
12850      * query specified by the allQuery config option (defaults to 'query')
12851      */
12852     triggerAction: 'query',
12853     /**
12854      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12855      * (defaults to 4, does not apply if editable = false)
12856      */
12857     minChars : 4,
12858     /**
12859      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12860      * delay (typeAheadDelay) if it matches a known value (defaults to false)
12861      */
12862     typeAhead: false,
12863     /**
12864      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12865      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12866      */
12867     queryDelay: 500,
12868     /**
12869      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12870      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
12871      */
12872     pageSize: 0,
12873     /**
12874      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
12875      * when editable = true (defaults to false)
12876      */
12877     selectOnFocus:false,
12878     /**
12879      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12880      */
12881     queryParam: 'query',
12882     /**
12883      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
12884      * when mode = 'remote' (defaults to 'Loading...')
12885      */
12886     loadingText: 'Loading...',
12887     /**
12888      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12889      */
12890     resizable: false,
12891     /**
12892      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12893      */
12894     handleHeight : 8,
12895     /**
12896      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12897      * traditional select (defaults to true)
12898      */
12899     editable: true,
12900     /**
12901      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12902      */
12903     allQuery: '',
12904     /**
12905      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12906      */
12907     mode: 'remote',
12908     /**
12909      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12910      * listWidth has a higher value)
12911      */
12912     minListWidth : 70,
12913     /**
12914      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12915      * allow the user to set arbitrary text into the field (defaults to false)
12916      */
12917     forceSelection:false,
12918     /**
12919      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12920      * if typeAhead = true (defaults to 250)
12921      */
12922     typeAheadDelay : 250,
12923     /**
12924      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12925      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12926      */
12927     valueNotFoundText : undefined,
12928     /**
12929      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12930      */
12931     blockFocus : false,
12932     
12933     /**
12934      * @cfg {Boolean} disableClear Disable showing of clear button.
12935      */
12936     disableClear : false,
12937     /**
12938      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
12939      */
12940     alwaysQuery : false,
12941     
12942     /**
12943      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
12944      */
12945     multiple : false,
12946     
12947     /**
12948      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12949      */
12950     invalidClass : "has-warning",
12951     
12952     /**
12953      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12954      */
12955     validClass : "has-success",
12956     
12957     /**
12958      * @cfg {Boolean} specialFilter (true|false) special filter default false
12959      */
12960     specialFilter : false,
12961     
12962     /**
12963      * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12964      */
12965     mobileTouchView : true,
12966     
12967     /**
12968      * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12969      */
12970     useNativeIOS : false,
12971     
12972     ios_options : false,
12973     
12974     //private
12975     addicon : false,
12976     editicon: false,
12977     
12978     page: 0,
12979     hasQuery: false,
12980     append: false,
12981     loadNext: false,
12982     autoFocus : true,
12983     tickable : false,
12984     btnPosition : 'right',
12985     triggerList : true,
12986     showToggleBtn : true,
12987     animate : true,
12988     emptyResultText: 'Empty',
12989     triggerText : 'Select',
12990     emptyTitle : '',
12991     
12992     // element that contains real text value.. (when hidden is used..)
12993     
12994     getAutoCreate : function()
12995     {   
12996         var cfg = false;
12997         //render
12998         /*
12999          * Render classic select for iso
13000          */
13001         
13002         if(Roo.isIOS && this.useNativeIOS){
13003             cfg = this.getAutoCreateNativeIOS();
13004             return cfg;
13005         }
13006         
13007         /*
13008          * Touch Devices
13009          */
13010         
13011         if(Roo.isTouch && this.mobileTouchView){
13012             cfg = this.getAutoCreateTouchView();
13013             return cfg;;
13014         }
13015         
13016         /*
13017          *  Normal ComboBox
13018          */
13019         if(!this.tickable){
13020             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13021             return cfg;
13022         }
13023         
13024         /*
13025          *  ComboBox with tickable selections
13026          */
13027              
13028         var align = this.labelAlign || this.parentLabelAlign();
13029         
13030         cfg = {
13031             cls : 'form-group roo-combobox-tickable' //input-group
13032         };
13033         
13034         var btn_text_select = '';
13035         var btn_text_done = '';
13036         var btn_text_cancel = '';
13037         
13038         if (this.btn_text_show) {
13039             btn_text_select = 'Select';
13040             btn_text_done = 'Done';
13041             btn_text_cancel = 'Cancel'; 
13042         }
13043         
13044         var buttons = {
13045             tag : 'div',
13046             cls : 'tickable-buttons',
13047             cn : [
13048                 {
13049                     tag : 'button',
13050                     type : 'button',
13051                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13052                     //html : this.triggerText
13053                     html: btn_text_select
13054                 },
13055                 {
13056                     tag : 'button',
13057                     type : 'button',
13058                     name : 'ok',
13059                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13060                     //html : 'Done'
13061                     html: btn_text_done
13062                 },
13063                 {
13064                     tag : 'button',
13065                     type : 'button',
13066                     name : 'cancel',
13067                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13068                     //html : 'Cancel'
13069                     html: btn_text_cancel
13070                 }
13071             ]
13072         };
13073         
13074         if(this.editable){
13075             buttons.cn.unshift({
13076                 tag: 'input',
13077                 cls: 'roo-select2-search-field-input'
13078             });
13079         }
13080         
13081         var _this = this;
13082         
13083         Roo.each(buttons.cn, function(c){
13084             if (_this.size) {
13085                 c.cls += ' btn-' + _this.size;
13086             }
13087
13088             if (_this.disabled) {
13089                 c.disabled = true;
13090             }
13091         });
13092         
13093         var box = {
13094             tag: 'div',
13095             cn: [
13096                 {
13097                     tag: 'input',
13098                     type : 'hidden',
13099                     cls: 'form-hidden-field'
13100                 },
13101                 {
13102                     tag: 'ul',
13103                     cls: 'roo-select2-choices',
13104                     cn:[
13105                         {
13106                             tag: 'li',
13107                             cls: 'roo-select2-search-field',
13108                             cn: [
13109                                 buttons
13110                             ]
13111                         }
13112                     ]
13113                 }
13114             ]
13115         };
13116         
13117         var combobox = {
13118             cls: 'roo-select2-container input-group roo-select2-container-multi',
13119             cn: [
13120                 box
13121 //                {
13122 //                    tag: 'ul',
13123 //                    cls: 'typeahead typeahead-long dropdown-menu',
13124 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
13125 //                }
13126             ]
13127         };
13128         
13129         if(this.hasFeedback && !this.allowBlank){
13130             
13131             var feedback = {
13132                 tag: 'span',
13133                 cls: 'glyphicon form-control-feedback'
13134             };
13135
13136             combobox.cn.push(feedback);
13137         }
13138         
13139         
13140         if (align ==='left' && this.fieldLabel.length) {
13141             
13142             cfg.cls += ' roo-form-group-label-left';
13143             
13144             cfg.cn = [
13145                 {
13146                     tag : 'i',
13147                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13148                     tooltip : 'This field is required'
13149                 },
13150                 {
13151                     tag: 'label',
13152                     'for' :  id,
13153                     cls : 'control-label',
13154                     html : this.fieldLabel
13155
13156                 },
13157                 {
13158                     cls : "", 
13159                     cn: [
13160                         combobox
13161                     ]
13162                 }
13163
13164             ];
13165             
13166             var labelCfg = cfg.cn[1];
13167             var contentCfg = cfg.cn[2];
13168             
13169
13170             if(this.indicatorpos == 'right'){
13171                 
13172                 cfg.cn = [
13173                     {
13174                         tag: 'label',
13175                         'for' :  id,
13176                         cls : 'control-label',
13177                         cn : [
13178                             {
13179                                 tag : 'span',
13180                                 html : this.fieldLabel
13181                             },
13182                             {
13183                                 tag : 'i',
13184                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13185                                 tooltip : 'This field is required'
13186                             }
13187                         ]
13188                     },
13189                     {
13190                         cls : "",
13191                         cn: [
13192                             combobox
13193                         ]
13194                     }
13195
13196                 ];
13197                 
13198                 
13199                 
13200                 labelCfg = cfg.cn[0];
13201                 contentCfg = cfg.cn[1];
13202             
13203             }
13204             
13205             if(this.labelWidth > 12){
13206                 labelCfg.style = "width: " + this.labelWidth + 'px';
13207             }
13208             
13209             if(this.labelWidth < 13 && this.labelmd == 0){
13210                 this.labelmd = this.labelWidth;
13211             }
13212             
13213             if(this.labellg > 0){
13214                 labelCfg.cls += ' col-lg-' + this.labellg;
13215                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13216             }
13217             
13218             if(this.labelmd > 0){
13219                 labelCfg.cls += ' col-md-' + this.labelmd;
13220                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13221             }
13222             
13223             if(this.labelsm > 0){
13224                 labelCfg.cls += ' col-sm-' + this.labelsm;
13225                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13226             }
13227             
13228             if(this.labelxs > 0){
13229                 labelCfg.cls += ' col-xs-' + this.labelxs;
13230                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13231             }
13232                 
13233                 
13234         } else if ( this.fieldLabel.length) {
13235 //                Roo.log(" label");
13236                  cfg.cn = [
13237                     {
13238                         tag : 'i',
13239                         cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13240                         tooltip : 'This field is required'
13241                     },
13242                     {
13243                         tag: 'label',
13244                         //cls : 'input-group-addon',
13245                         html : this.fieldLabel
13246                     },
13247                     combobox
13248                 ];
13249                 
13250                 if(this.indicatorpos == 'right'){
13251                     cfg.cn = [
13252                         {
13253                             tag: 'label',
13254                             //cls : 'input-group-addon',
13255                             html : this.fieldLabel
13256                         },
13257                         {
13258                             tag : 'i',
13259                             cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13260                             tooltip : 'This field is required'
13261                         },
13262                         combobox
13263                     ];
13264                     
13265                 }
13266
13267         } else {
13268             
13269 //                Roo.log(" no label && no align");
13270                 cfg = combobox
13271                      
13272                 
13273         }
13274          
13275         var settings=this;
13276         ['xs','sm','md','lg'].map(function(size){
13277             if (settings[size]) {
13278                 cfg.cls += ' col-' + size + '-' + settings[size];
13279             }
13280         });
13281         
13282         return cfg;
13283         
13284     },
13285     
13286     _initEventsCalled : false,
13287     
13288     // private
13289     initEvents: function()
13290     {   
13291         if (this._initEventsCalled) { // as we call render... prevent looping...
13292             return;
13293         }
13294         this._initEventsCalled = true;
13295         
13296         if (!this.store) {
13297             throw "can not find store for combo";
13298         }
13299         
13300         this.indicator = this.indicatorEl();
13301         
13302         this.store = Roo.factory(this.store, Roo.data);
13303         this.store.parent = this;
13304         
13305         // if we are building from html. then this element is so complex, that we can not really
13306         // use the rendered HTML.
13307         // so we have to trash and replace the previous code.
13308         if (Roo.XComponent.build_from_html) {
13309             // remove this element....
13310             var e = this.el.dom, k=0;
13311             while (e ) { e = e.previousSibling;  ++k;}
13312
13313             this.el.remove();
13314             
13315             this.el=false;
13316             this.rendered = false;
13317             
13318             this.render(this.parent().getChildContainer(true), k);
13319         }
13320         
13321         if(Roo.isIOS && this.useNativeIOS){
13322             this.initIOSView();
13323             return;
13324         }
13325         
13326         /*
13327          * Touch Devices
13328          */
13329         
13330         if(Roo.isTouch && this.mobileTouchView){
13331             this.initTouchView();
13332             return;
13333         }
13334         
13335         if(this.tickable){
13336             this.initTickableEvents();
13337             return;
13338         }
13339         
13340         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13341         
13342         if(this.hiddenName){
13343             
13344             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13345             
13346             this.hiddenField.dom.value =
13347                 this.hiddenValue !== undefined ? this.hiddenValue :
13348                 this.value !== undefined ? this.value : '';
13349
13350             // prevent input submission
13351             this.el.dom.removeAttribute('name');
13352             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13353              
13354              
13355         }
13356         //if(Roo.isGecko){
13357         //    this.el.dom.setAttribute('autocomplete', 'off');
13358         //}
13359         
13360         var cls = 'x-combo-list';
13361         
13362         //this.list = new Roo.Layer({
13363         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13364         //});
13365         
13366         var _this = this;
13367         
13368         (function(){
13369             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13370             _this.list.setWidth(lw);
13371         }).defer(100);
13372         
13373         this.list.on('mouseover', this.onViewOver, this);
13374         this.list.on('mousemove', this.onViewMove, this);
13375         this.list.on('scroll', this.onViewScroll, this);
13376         
13377         /*
13378         this.list.swallowEvent('mousewheel');
13379         this.assetHeight = 0;
13380
13381         if(this.title){
13382             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13383             this.assetHeight += this.header.getHeight();
13384         }
13385
13386         this.innerList = this.list.createChild({cls:cls+'-inner'});
13387         this.innerList.on('mouseover', this.onViewOver, this);
13388         this.innerList.on('mousemove', this.onViewMove, this);
13389         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13390         
13391         if(this.allowBlank && !this.pageSize && !this.disableClear){
13392             this.footer = this.list.createChild({cls:cls+'-ft'});
13393             this.pageTb = new Roo.Toolbar(this.footer);
13394            
13395         }
13396         if(this.pageSize){
13397             this.footer = this.list.createChild({cls:cls+'-ft'});
13398             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13399                     {pageSize: this.pageSize});
13400             
13401         }
13402         
13403         if (this.pageTb && this.allowBlank && !this.disableClear) {
13404             var _this = this;
13405             this.pageTb.add(new Roo.Toolbar.Fill(), {
13406                 cls: 'x-btn-icon x-btn-clear',
13407                 text: '&#160;',
13408                 handler: function()
13409                 {
13410                     _this.collapse();
13411                     _this.clearValue();
13412                     _this.onSelect(false, -1);
13413                 }
13414             });
13415         }
13416         if (this.footer) {
13417             this.assetHeight += this.footer.getHeight();
13418         }
13419         */
13420             
13421         if(!this.tpl){
13422             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13423         }
13424
13425         this.view = new Roo.View(this.list, this.tpl, {
13426             singleSelect:true, store: this.store, selectedClass: this.selectedClass
13427         });
13428         //this.view.wrapEl.setDisplayed(false);
13429         this.view.on('click', this.onViewClick, this);
13430         
13431         
13432         this.store.on('beforeload', this.onBeforeLoad, this);
13433         this.store.on('load', this.onLoad, this);
13434         this.store.on('loadexception', this.onLoadException, this);
13435         /*
13436         if(this.resizable){
13437             this.resizer = new Roo.Resizable(this.list,  {
13438                pinned:true, handles:'se'
13439             });
13440             this.resizer.on('resize', function(r, w, h){
13441                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13442                 this.listWidth = w;
13443                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13444                 this.restrictHeight();
13445             }, this);
13446             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13447         }
13448         */
13449         if(!this.editable){
13450             this.editable = true;
13451             this.setEditable(false);
13452         }
13453         
13454         /*
13455         
13456         if (typeof(this.events.add.listeners) != 'undefined') {
13457             
13458             this.addicon = this.wrap.createChild(
13459                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
13460        
13461             this.addicon.on('click', function(e) {
13462                 this.fireEvent('add', this);
13463             }, this);
13464         }
13465         if (typeof(this.events.edit.listeners) != 'undefined') {
13466             
13467             this.editicon = this.wrap.createChild(
13468                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
13469             if (this.addicon) {
13470                 this.editicon.setStyle('margin-left', '40px');
13471             }
13472             this.editicon.on('click', function(e) {
13473                 
13474                 // we fire even  if inothing is selected..
13475                 this.fireEvent('edit', this, this.lastData );
13476                 
13477             }, this);
13478         }
13479         */
13480         
13481         this.keyNav = new Roo.KeyNav(this.inputEl(), {
13482             "up" : function(e){
13483                 this.inKeyMode = true;
13484                 this.selectPrev();
13485             },
13486
13487             "down" : function(e){
13488                 if(!this.isExpanded()){
13489                     this.onTriggerClick();
13490                 }else{
13491                     this.inKeyMode = true;
13492                     this.selectNext();
13493                 }
13494             },
13495
13496             "enter" : function(e){
13497 //                this.onViewClick();
13498                 //return true;
13499                 this.collapse();
13500                 
13501                 if(this.fireEvent("specialkey", this, e)){
13502                     this.onViewClick(false);
13503                 }
13504                 
13505                 return true;
13506             },
13507
13508             "esc" : function(e){
13509                 this.collapse();
13510             },
13511
13512             "tab" : function(e){
13513                 this.collapse();
13514                 
13515                 if(this.fireEvent("specialkey", this, e)){
13516                     this.onViewClick(false);
13517                 }
13518                 
13519                 return true;
13520             },
13521
13522             scope : this,
13523
13524             doRelay : function(foo, bar, hname){
13525                 if(hname == 'down' || this.scope.isExpanded()){
13526                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13527                 }
13528                 return true;
13529             },
13530
13531             forceKeyDown: true
13532         });
13533         
13534         
13535         this.queryDelay = Math.max(this.queryDelay || 10,
13536                 this.mode == 'local' ? 10 : 250);
13537         
13538         
13539         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13540         
13541         if(this.typeAhead){
13542             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13543         }
13544         if(this.editable !== false){
13545             this.inputEl().on("keyup", this.onKeyUp, this);
13546         }
13547         if(this.forceSelection){
13548             this.inputEl().on('blur', this.doForce, this);
13549         }
13550         
13551         if(this.multiple){
13552             this.choices = this.el.select('ul.roo-select2-choices', true).first();
13553             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13554         }
13555     },
13556     
13557     initTickableEvents: function()
13558     {   
13559         this.createList();
13560         
13561         if(this.hiddenName){
13562             
13563             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13564             
13565             this.hiddenField.dom.value =
13566                 this.hiddenValue !== undefined ? this.hiddenValue :
13567                 this.value !== undefined ? this.value : '';
13568
13569             // prevent input submission
13570             this.el.dom.removeAttribute('name');
13571             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13572              
13573              
13574         }
13575         
13576 //        this.list = this.el.select('ul.dropdown-menu',true).first();
13577         
13578         this.choices = this.el.select('ul.roo-select2-choices', true).first();
13579         this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13580         if(this.triggerList){
13581             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13582         }
13583          
13584         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13585         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13586         
13587         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13588         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13589         
13590         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13591         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13592         
13593         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13594         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13595         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13596         
13597         this.okBtn.hide();
13598         this.cancelBtn.hide();
13599         
13600         var _this = this;
13601         
13602         (function(){
13603             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13604             _this.list.setWidth(lw);
13605         }).defer(100);
13606         
13607         this.list.on('mouseover', this.onViewOver, this);
13608         this.list.on('mousemove', this.onViewMove, this);
13609         
13610         this.list.on('scroll', this.onViewScroll, this);
13611         
13612         if(!this.tpl){
13613             this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}" type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13614         }
13615
13616         this.view = new Roo.View(this.list, this.tpl, {
13617             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13618         });
13619         
13620         //this.view.wrapEl.setDisplayed(false);
13621         this.view.on('click', this.onViewClick, this);
13622         
13623         
13624         
13625         this.store.on('beforeload', this.onBeforeLoad, this);
13626         this.store.on('load', this.onLoad, this);
13627         this.store.on('loadexception', this.onLoadException, this);
13628         
13629         if(this.editable){
13630             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13631                 "up" : function(e){
13632                     this.inKeyMode = true;
13633                     this.selectPrev();
13634                 },
13635
13636                 "down" : function(e){
13637                     this.inKeyMode = true;
13638                     this.selectNext();
13639                 },
13640
13641                 "enter" : function(e){
13642                     if(this.fireEvent("specialkey", this, e)){
13643                         this.onViewClick(false);
13644                     }
13645                     
13646                     return true;
13647                 },
13648
13649                 "esc" : function(e){
13650                     this.onTickableFooterButtonClick(e, false, false);
13651                 },
13652
13653                 "tab" : function(e){
13654                     this.fireEvent("specialkey", this, e);
13655                     
13656                     this.onTickableFooterButtonClick(e, false, false);
13657                     
13658                     return true;
13659                 },
13660
13661                 scope : this,
13662
13663                 doRelay : function(e, fn, key){
13664                     if(this.scope.isExpanded()){
13665                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13666                     }
13667                     return true;
13668                 },
13669
13670                 forceKeyDown: true
13671             });
13672         }
13673         
13674         this.queryDelay = Math.max(this.queryDelay || 10,
13675                 this.mode == 'local' ? 10 : 250);
13676         
13677         
13678         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13679         
13680         if(this.typeAhead){
13681             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13682         }
13683         
13684         if(this.editable !== false){
13685             this.tickableInputEl().on("keyup", this.onKeyUp, this);
13686         }
13687         
13688         this.indicator = this.indicatorEl();
13689         
13690         if(this.indicator){
13691             this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13692             this.indicator.hide();
13693         }
13694         
13695     },
13696
13697     onDestroy : function(){
13698         if(this.view){
13699             this.view.setStore(null);
13700             this.view.el.removeAllListeners();
13701             this.view.el.remove();
13702             this.view.purgeListeners();
13703         }
13704         if(this.list){
13705             this.list.dom.innerHTML  = '';
13706         }
13707         
13708         if(this.store){
13709             this.store.un('beforeload', this.onBeforeLoad, this);
13710             this.store.un('load', this.onLoad, this);
13711             this.store.un('loadexception', this.onLoadException, this);
13712         }
13713         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13714     },
13715
13716     // private
13717     fireKey : function(e){
13718         if(e.isNavKeyPress() && !this.list.isVisible()){
13719             this.fireEvent("specialkey", this, e);
13720         }
13721     },
13722
13723     // private
13724     onResize: function(w, h){
13725 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13726 //        
13727 //        if(typeof w != 'number'){
13728 //            // we do not handle it!?!?
13729 //            return;
13730 //        }
13731 //        var tw = this.trigger.getWidth();
13732 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
13733 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
13734 //        var x = w - tw;
13735 //        this.inputEl().setWidth( this.adjustWidth('input', x));
13736 //            
13737 //        //this.trigger.setStyle('left', x+'px');
13738 //        
13739 //        if(this.list && this.listWidth === undefined){
13740 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13741 //            this.list.setWidth(lw);
13742 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13743 //        }
13744         
13745     
13746         
13747     },
13748
13749     /**
13750      * Allow or prevent the user from directly editing the field text.  If false is passed,
13751      * the user will only be able to select from the items defined in the dropdown list.  This method
13752      * is the runtime equivalent of setting the 'editable' config option at config time.
13753      * @param {Boolean} value True to allow the user to directly edit the field text
13754      */
13755     setEditable : function(value){
13756         if(value == this.editable){
13757             return;
13758         }
13759         this.editable = value;
13760         if(!value){
13761             this.inputEl().dom.setAttribute('readOnly', true);
13762             this.inputEl().on('mousedown', this.onTriggerClick,  this);
13763             this.inputEl().addClass('x-combo-noedit');
13764         }else{
13765             this.inputEl().dom.setAttribute('readOnly', false);
13766             this.inputEl().un('mousedown', this.onTriggerClick,  this);
13767             this.inputEl().removeClass('x-combo-noedit');
13768         }
13769     },
13770
13771     // private
13772     
13773     onBeforeLoad : function(combo,opts){
13774         if(!this.hasFocus){
13775             return;
13776         }
13777          if (!opts.add) {
13778             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13779          }
13780         this.restrictHeight();
13781         this.selectedIndex = -1;
13782     },
13783
13784     // private
13785     onLoad : function(){
13786         
13787         this.hasQuery = false;
13788         
13789         if(!this.hasFocus){
13790             return;
13791         }
13792         
13793         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13794             this.loading.hide();
13795         }
13796         
13797         if(this.store.getCount() > 0){
13798             
13799             this.expand();
13800             this.restrictHeight();
13801             if(this.lastQuery == this.allQuery){
13802                 if(this.editable && !this.tickable){
13803                     this.inputEl().dom.select();
13804                 }
13805                 
13806                 if(
13807                     !this.selectByValue(this.value, true) &&
13808                     this.autoFocus && 
13809                     (
13810                         !this.store.lastOptions ||
13811                         typeof(this.store.lastOptions.add) == 'undefined' || 
13812                         this.store.lastOptions.add != true
13813                     )
13814                 ){
13815                     this.select(0, true);
13816                 }
13817             }else{
13818                 if(this.autoFocus){
13819                     this.selectNext();
13820                 }
13821                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13822                     this.taTask.delay(this.typeAheadDelay);
13823                 }
13824             }
13825         }else{
13826             this.onEmptyResults();
13827         }
13828         
13829         //this.el.focus();
13830     },
13831     // private
13832     onLoadException : function()
13833     {
13834         this.hasQuery = false;
13835         
13836         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13837             this.loading.hide();
13838         }
13839         
13840         if(this.tickable && this.editable){
13841             return;
13842         }
13843         
13844         this.collapse();
13845         // only causes errors at present
13846         //Roo.log(this.store.reader.jsonData);
13847         //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13848             // fixme
13849             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13850         //}
13851         
13852         
13853     },
13854     // private
13855     onTypeAhead : function(){
13856         if(this.store.getCount() > 0){
13857             var r = this.store.getAt(0);
13858             var newValue = r.data[this.displayField];
13859             var len = newValue.length;
13860             var selStart = this.getRawValue().length;
13861             
13862             if(selStart != len){
13863                 this.setRawValue(newValue);
13864                 this.selectText(selStart, newValue.length);
13865             }
13866         }
13867     },
13868
13869     // private
13870     onSelect : function(record, index){
13871         
13872         if(this.fireEvent('beforeselect', this, record, index) !== false){
13873         
13874             this.setFromData(index > -1 ? record.data : false);
13875             
13876             this.collapse();
13877             this.fireEvent('select', this, record, index);
13878         }
13879     },
13880
13881     /**
13882      * Returns the currently selected field value or empty string if no value is set.
13883      * @return {String} value The selected value
13884      */
13885     getValue : function()
13886     {
13887         if(Roo.isIOS && this.useNativeIOS){
13888             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13889         }
13890         
13891         if(this.multiple){
13892             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13893         }
13894         
13895         if(this.valueField){
13896             return typeof this.value != 'undefined' ? this.value : '';
13897         }else{
13898             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13899         }
13900     },
13901     
13902     getRawValue : function()
13903     {
13904         if(Roo.isIOS && this.useNativeIOS){
13905             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13906         }
13907         
13908         var v = this.inputEl().getValue();
13909         
13910         return v;
13911     },
13912
13913     /**
13914      * Clears any text/value currently set in the field
13915      */
13916     clearValue : function(){
13917         
13918         if(this.hiddenField){
13919             this.hiddenField.dom.value = '';
13920         }
13921         this.value = '';
13922         this.setRawValue('');
13923         this.lastSelectionText = '';
13924         this.lastData = false;
13925         
13926         var close = this.closeTriggerEl();
13927         
13928         if(close){
13929             close.hide();
13930         }
13931         
13932         this.validate();
13933         
13934     },
13935
13936     /**
13937      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
13938      * will be displayed in the field.  If the value does not match the data value of an existing item,
13939      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13940      * Otherwise the field will be blank (although the value will still be set).
13941      * @param {String} value The value to match
13942      */
13943     setValue : function(v)
13944     {
13945         if(Roo.isIOS && this.useNativeIOS){
13946             this.setIOSValue(v);
13947             return;
13948         }
13949         
13950         if(this.multiple){
13951             this.syncValue();
13952             return;
13953         }
13954         
13955         var text = v;
13956         if(this.valueField){
13957             var r = this.findRecord(this.valueField, v);
13958             if(r){
13959                 text = r.data[this.displayField];
13960             }else if(this.valueNotFoundText !== undefined){
13961                 text = this.valueNotFoundText;
13962             }
13963         }
13964         this.lastSelectionText = text;
13965         if(this.hiddenField){
13966             this.hiddenField.dom.value = v;
13967         }
13968         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13969         this.value = v;
13970         
13971         var close = this.closeTriggerEl();
13972         
13973         if(close){
13974             (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13975         }
13976         
13977         this.validate();
13978     },
13979     /**
13980      * @property {Object} the last set data for the element
13981      */
13982     
13983     lastData : false,
13984     /**
13985      * Sets the value of the field based on a object which is related to the record format for the store.
13986      * @param {Object} value the value to set as. or false on reset?
13987      */
13988     setFromData : function(o){
13989         
13990         if(this.multiple){
13991             this.addItem(o);
13992             return;
13993         }
13994             
13995         var dv = ''; // display value
13996         var vv = ''; // value value..
13997         this.lastData = o;
13998         if (this.displayField) {
13999             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14000         } else {
14001             // this is an error condition!!!
14002             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14003         }
14004         
14005         if(this.valueField){
14006             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14007         }
14008         
14009         var close = this.closeTriggerEl();
14010         
14011         if(close){
14012             if(dv.length || vv * 1 > 0){
14013                 close.show() ;
14014                 this.blockFocus=true;
14015             } else {
14016                 close.hide();
14017             }             
14018         }
14019         
14020         if(this.hiddenField){
14021             this.hiddenField.dom.value = vv;
14022             
14023             this.lastSelectionText = dv;
14024             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14025             this.value = vv;
14026             return;
14027         }
14028         // no hidden field.. - we store the value in 'value', but still display
14029         // display field!!!!
14030         this.lastSelectionText = dv;
14031         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14032         this.value = vv;
14033         
14034         
14035         
14036     },
14037     // private
14038     reset : function(){
14039         // overridden so that last data is reset..
14040         
14041         if(this.multiple){
14042             this.clearItem();
14043             return;
14044         }
14045         
14046         this.setValue(this.originalValue);
14047         //this.clearInvalid();
14048         this.lastData = false;
14049         if (this.view) {
14050             this.view.clearSelections();
14051         }
14052         
14053         this.validate();
14054     },
14055     // private
14056     findRecord : function(prop, value){
14057         var record;
14058         if(this.store.getCount() > 0){
14059             this.store.each(function(r){
14060                 if(r.data[prop] == value){
14061                     record = r;
14062                     return false;
14063                 }
14064                 return true;
14065             });
14066         }
14067         return record;
14068     },
14069     
14070     getName: function()
14071     {
14072         // returns hidden if it's set..
14073         if (!this.rendered) {return ''};
14074         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
14075         
14076     },
14077     // private
14078     onViewMove : function(e, t){
14079         this.inKeyMode = false;
14080     },
14081
14082     // private
14083     onViewOver : function(e, t){
14084         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14085             return;
14086         }
14087         var item = this.view.findItemFromChild(t);
14088         
14089         if(item){
14090             var index = this.view.indexOf(item);
14091             this.select(index, false);
14092         }
14093     },
14094
14095     // private
14096     onViewClick : function(view, doFocus, el, e)
14097     {
14098         var index = this.view.getSelectedIndexes()[0];
14099         
14100         var r = this.store.getAt(index);
14101         
14102         if(this.tickable){
14103             
14104             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14105                 return;
14106             }
14107             
14108             var rm = false;
14109             var _this = this;
14110             
14111             Roo.each(this.tickItems, function(v,k){
14112                 
14113                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14114                     Roo.log(v);
14115                     _this.tickItems.splice(k, 1);
14116                     
14117                     if(typeof(e) == 'undefined' && view == false){
14118                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14119                     }
14120                     
14121                     rm = true;
14122                     return;
14123                 }
14124             });
14125             
14126             if(rm){
14127                 return;
14128             }
14129             
14130             if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14131                 this.tickItems.push(r.data);
14132             }
14133             
14134             if(typeof(e) == 'undefined' && view == false){
14135                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14136             }
14137                     
14138             return;
14139         }
14140         
14141         if(r){
14142             this.onSelect(r, index);
14143         }
14144         if(doFocus !== false && !this.blockFocus){
14145             this.inputEl().focus();
14146         }
14147     },
14148
14149     // private
14150     restrictHeight : function(){
14151         //this.innerList.dom.style.height = '';
14152         //var inner = this.innerList.dom;
14153         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14154         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14155         //this.list.beginUpdate();
14156         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14157         this.list.alignTo(this.inputEl(), this.listAlign);
14158         this.list.alignTo(this.inputEl(), this.listAlign);
14159         //this.list.endUpdate();
14160     },
14161
14162     // private
14163     onEmptyResults : function(){
14164         
14165         if(this.tickable && this.editable){
14166             this.hasFocus = false;
14167             this.restrictHeight();
14168             return;
14169         }
14170         
14171         this.collapse();
14172     },
14173
14174     /**
14175      * Returns true if the dropdown list is expanded, else false.
14176      */
14177     isExpanded : function(){
14178         return this.list.isVisible();
14179     },
14180
14181     /**
14182      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14183      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14184      * @param {String} value The data value of the item to select
14185      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14186      * selected item if it is not currently in view (defaults to true)
14187      * @return {Boolean} True if the value matched an item in the list, else false
14188      */
14189     selectByValue : function(v, scrollIntoView){
14190         if(v !== undefined && v !== null){
14191             var r = this.findRecord(this.valueField || this.displayField, v);
14192             if(r){
14193                 this.select(this.store.indexOf(r), scrollIntoView);
14194                 return true;
14195             }
14196         }
14197         return false;
14198     },
14199
14200     /**
14201      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14202      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14203      * @param {Number} index The zero-based index of the list item to select
14204      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14205      * selected item if it is not currently in view (defaults to true)
14206      */
14207     select : function(index, scrollIntoView){
14208         this.selectedIndex = index;
14209         this.view.select(index);
14210         if(scrollIntoView !== false){
14211             var el = this.view.getNode(index);
14212             /*
14213              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14214              */
14215             if(el){
14216                 this.list.scrollChildIntoView(el, false);
14217             }
14218         }
14219     },
14220
14221     // private
14222     selectNext : function(){
14223         var ct = this.store.getCount();
14224         if(ct > 0){
14225             if(this.selectedIndex == -1){
14226                 this.select(0);
14227             }else if(this.selectedIndex < ct-1){
14228                 this.select(this.selectedIndex+1);
14229             }
14230         }
14231     },
14232
14233     // private
14234     selectPrev : function(){
14235         var ct = this.store.getCount();
14236         if(ct > 0){
14237             if(this.selectedIndex == -1){
14238                 this.select(0);
14239             }else if(this.selectedIndex != 0){
14240                 this.select(this.selectedIndex-1);
14241             }
14242         }
14243     },
14244
14245     // private
14246     onKeyUp : function(e){
14247         if(this.editable !== false && !e.isSpecialKey()){
14248             this.lastKey = e.getKey();
14249             this.dqTask.delay(this.queryDelay);
14250         }
14251     },
14252
14253     // private
14254     validateBlur : function(){
14255         return !this.list || !this.list.isVisible();   
14256     },
14257
14258     // private
14259     initQuery : function(){
14260         
14261         var v = this.getRawValue();
14262         
14263         if(this.tickable && this.editable){
14264             v = this.tickableInputEl().getValue();
14265         }
14266         
14267         this.doQuery(v);
14268     },
14269
14270     // private
14271     doForce : function(){
14272         if(this.inputEl().dom.value.length > 0){
14273             this.inputEl().dom.value =
14274                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14275              
14276         }
14277     },
14278
14279     /**
14280      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
14281      * query allowing the query action to be canceled if needed.
14282      * @param {String} query The SQL query to execute
14283      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14284      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
14285      * saved in the current store (defaults to false)
14286      */
14287     doQuery : function(q, forceAll){
14288         
14289         if(q === undefined || q === null){
14290             q = '';
14291         }
14292         var qe = {
14293             query: q,
14294             forceAll: forceAll,
14295             combo: this,
14296             cancel:false
14297         };
14298         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14299             return false;
14300         }
14301         q = qe.query;
14302         
14303         forceAll = qe.forceAll;
14304         if(forceAll === true || (q.length >= this.minChars)){
14305             
14306             this.hasQuery = true;
14307             
14308             if(this.lastQuery != q || this.alwaysQuery){
14309                 this.lastQuery = q;
14310                 if(this.mode == 'local'){
14311                     this.selectedIndex = -1;
14312                     if(forceAll){
14313                         this.store.clearFilter();
14314                     }else{
14315                         
14316                         if(this.specialFilter){
14317                             this.fireEvent('specialfilter', this);
14318                             this.onLoad();
14319                             return;
14320                         }
14321                         
14322                         this.store.filter(this.displayField, q);
14323                     }
14324                     
14325                     this.store.fireEvent("datachanged", this.store);
14326                     
14327                     this.onLoad();
14328                     
14329                     
14330                 }else{
14331                     
14332                     this.store.baseParams[this.queryParam] = q;
14333                     
14334                     var options = {params : this.getParams(q)};
14335                     
14336                     if(this.loadNext){
14337                         options.add = true;
14338                         options.params.start = this.page * this.pageSize;
14339                     }
14340                     
14341                     this.store.load(options);
14342                     
14343                     /*
14344                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
14345                      *  we should expand the list on onLoad
14346                      *  so command out it
14347                      */
14348 //                    this.expand();
14349                 }
14350             }else{
14351                 this.selectedIndex = -1;
14352                 this.onLoad();   
14353             }
14354         }
14355         
14356         this.loadNext = false;
14357     },
14358     
14359     // private
14360     getParams : function(q){
14361         var p = {};
14362         //p[this.queryParam] = q;
14363         
14364         if(this.pageSize){
14365             p.start = 0;
14366             p.limit = this.pageSize;
14367         }
14368         return p;
14369     },
14370
14371     /**
14372      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14373      */
14374     collapse : function(){
14375         if(!this.isExpanded()){
14376             return;
14377         }
14378         
14379         this.list.hide();
14380         
14381         this.hasFocus = false;
14382         
14383         if(this.tickable){
14384             this.okBtn.hide();
14385             this.cancelBtn.hide();
14386             this.trigger.show();
14387             
14388             if(this.editable){
14389                 this.tickableInputEl().dom.value = '';
14390                 this.tickableInputEl().blur();
14391             }
14392             
14393         }
14394         
14395         Roo.get(document).un('mousedown', this.collapseIf, this);
14396         Roo.get(document).un('mousewheel', this.collapseIf, this);
14397         if (!this.editable) {
14398             Roo.get(document).un('keydown', this.listKeyPress, this);
14399         }
14400         this.fireEvent('collapse', this);
14401         
14402         this.validate();
14403     },
14404
14405     // private
14406     collapseIf : function(e){
14407         var in_combo  = e.within(this.el);
14408         var in_list =  e.within(this.list);
14409         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14410         
14411         if (in_combo || in_list || is_list) {
14412             //e.stopPropagation();
14413             return;
14414         }
14415         
14416         if(this.tickable){
14417             this.onTickableFooterButtonClick(e, false, false);
14418         }
14419
14420         this.collapse();
14421         
14422     },
14423
14424     /**
14425      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14426      */
14427     expand : function(){
14428        
14429         if(this.isExpanded() || !this.hasFocus){
14430             return;
14431         }
14432         
14433         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14434         this.list.setWidth(lw);
14435         
14436         Roo.log('expand');
14437         
14438         this.list.show();
14439         
14440         this.restrictHeight();
14441         
14442         if(this.tickable){
14443             
14444             this.tickItems = Roo.apply([], this.item);
14445             
14446             this.okBtn.show();
14447             this.cancelBtn.show();
14448             this.trigger.hide();
14449             
14450             if(this.editable){
14451                 this.tickableInputEl().focus();
14452             }
14453             
14454         }
14455         
14456         Roo.get(document).on('mousedown', this.collapseIf, this);
14457         Roo.get(document).on('mousewheel', this.collapseIf, this);
14458         if (!this.editable) {
14459             Roo.get(document).on('keydown', this.listKeyPress, this);
14460         }
14461         
14462         this.fireEvent('expand', this);
14463     },
14464
14465     // private
14466     // Implements the default empty TriggerField.onTriggerClick function
14467     onTriggerClick : function(e)
14468     {
14469         Roo.log('trigger click');
14470         
14471         if(this.disabled || !this.triggerList){
14472             return;
14473         }
14474         
14475         this.page = 0;
14476         this.loadNext = false;
14477         
14478         if(this.isExpanded()){
14479             this.collapse();
14480             if (!this.blockFocus) {
14481                 this.inputEl().focus();
14482             }
14483             
14484         }else {
14485             this.hasFocus = true;
14486             if(this.triggerAction == 'all') {
14487                 this.doQuery(this.allQuery, true);
14488             } else {
14489                 this.doQuery(this.getRawValue());
14490             }
14491             if (!this.blockFocus) {
14492                 this.inputEl().focus();
14493             }
14494         }
14495     },
14496     
14497     onTickableTriggerClick : function(e)
14498     {
14499         if(this.disabled){
14500             return;
14501         }
14502         
14503         this.page = 0;
14504         this.loadNext = false;
14505         this.hasFocus = true;
14506         
14507         if(this.triggerAction == 'all') {
14508             this.doQuery(this.allQuery, true);
14509         } else {
14510             this.doQuery(this.getRawValue());
14511         }
14512     },
14513     
14514     onSearchFieldClick : function(e)
14515     {
14516         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14517             this.onTickableFooterButtonClick(e, false, false);
14518             return;
14519         }
14520         
14521         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14522             return;
14523         }
14524         
14525         this.page = 0;
14526         this.loadNext = false;
14527         this.hasFocus = true;
14528         
14529         if(this.triggerAction == 'all') {
14530             this.doQuery(this.allQuery, true);
14531         } else {
14532             this.doQuery(this.getRawValue());
14533         }
14534     },
14535     
14536     listKeyPress : function(e)
14537     {
14538         //Roo.log('listkeypress');
14539         // scroll to first matching element based on key pres..
14540         if (e.isSpecialKey()) {
14541             return false;
14542         }
14543         var k = String.fromCharCode(e.getKey()).toUpperCase();
14544         //Roo.log(k);
14545         var match  = false;
14546         var csel = this.view.getSelectedNodes();
14547         var cselitem = false;
14548         if (csel.length) {
14549             var ix = this.view.indexOf(csel[0]);
14550             cselitem  = this.store.getAt(ix);
14551             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14552                 cselitem = false;
14553             }
14554             
14555         }
14556         
14557         this.store.each(function(v) { 
14558             if (cselitem) {
14559                 // start at existing selection.
14560                 if (cselitem.id == v.id) {
14561                     cselitem = false;
14562                 }
14563                 return true;
14564             }
14565                 
14566             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14567                 match = this.store.indexOf(v);
14568                 return false;
14569             }
14570             return true;
14571         }, this);
14572         
14573         if (match === false) {
14574             return true; // no more action?
14575         }
14576         // scroll to?
14577         this.view.select(match);
14578         var sn = Roo.get(this.view.getSelectedNodes()[0]);
14579         sn.scrollIntoView(sn.dom.parentNode, false);
14580     },
14581     
14582     onViewScroll : function(e, t){
14583         
14584         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){
14585             return;
14586         }
14587         
14588         this.hasQuery = true;
14589         
14590         this.loading = this.list.select('.loading', true).first();
14591         
14592         if(this.loading === null){
14593             this.list.createChild({
14594                 tag: 'div',
14595                 cls: 'loading roo-select2-more-results roo-select2-active',
14596                 html: 'Loading more results...'
14597             });
14598             
14599             this.loading = this.list.select('.loading', true).first();
14600             
14601             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14602             
14603             this.loading.hide();
14604         }
14605         
14606         this.loading.show();
14607         
14608         var _combo = this;
14609         
14610         this.page++;
14611         this.loadNext = true;
14612         
14613         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14614         
14615         return;
14616     },
14617     
14618     addItem : function(o)
14619     {   
14620         var dv = ''; // display value
14621         
14622         if (this.displayField) {
14623             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14624         } else {
14625             // this is an error condition!!!
14626             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14627         }
14628         
14629         if(!dv.length){
14630             return;
14631         }
14632         
14633         var choice = this.choices.createChild({
14634             tag: 'li',
14635             cls: 'roo-select2-search-choice',
14636             cn: [
14637                 {
14638                     tag: 'div',
14639                     html: dv
14640                 },
14641                 {
14642                     tag: 'a',
14643                     href: '#',
14644                     cls: 'roo-select2-search-choice-close fa fa-times',
14645                     tabindex: '-1'
14646                 }
14647             ]
14648             
14649         }, this.searchField);
14650         
14651         var close = choice.select('a.roo-select2-search-choice-close', true).first();
14652         
14653         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14654         
14655         this.item.push(o);
14656         
14657         this.lastData = o;
14658         
14659         this.syncValue();
14660         
14661         this.inputEl().dom.value = '';
14662         
14663         this.validate();
14664     },
14665     
14666     onRemoveItem : function(e, _self, o)
14667     {
14668         e.preventDefault();
14669         
14670         this.lastItem = Roo.apply([], this.item);
14671         
14672         var index = this.item.indexOf(o.data) * 1;
14673         
14674         if( index < 0){
14675             Roo.log('not this item?!');
14676             return;
14677         }
14678         
14679         this.item.splice(index, 1);
14680         o.item.remove();
14681         
14682         this.syncValue();
14683         
14684         this.fireEvent('remove', this, e);
14685         
14686         this.validate();
14687         
14688     },
14689     
14690     syncValue : function()
14691     {
14692         if(!this.item.length){
14693             this.clearValue();
14694             return;
14695         }
14696             
14697         var value = [];
14698         var _this = this;
14699         Roo.each(this.item, function(i){
14700             if(_this.valueField){
14701                 value.push(i[_this.valueField]);
14702                 return;
14703             }
14704
14705             value.push(i);
14706         });
14707
14708         this.value = value.join(',');
14709
14710         if(this.hiddenField){
14711             this.hiddenField.dom.value = this.value;
14712         }
14713         
14714         this.store.fireEvent("datachanged", this.store);
14715         
14716         this.validate();
14717     },
14718     
14719     clearItem : function()
14720     {
14721         if(!this.multiple){
14722             return;
14723         }
14724         
14725         this.item = [];
14726         
14727         Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14728            c.remove();
14729         });
14730         
14731         this.syncValue();
14732         
14733         this.validate();
14734         
14735         if(this.tickable && !Roo.isTouch){
14736             this.view.refresh();
14737         }
14738     },
14739     
14740     inputEl: function ()
14741     {
14742         if(Roo.isIOS && this.useNativeIOS){
14743             return this.el.select('select.roo-ios-select', true).first();
14744         }
14745         
14746         if(Roo.isTouch && this.mobileTouchView){
14747             return this.el.select('input.form-control',true).first();
14748         }
14749         
14750         if(this.tickable){
14751             return this.searchField;
14752         }
14753         
14754         return this.el.select('input.form-control',true).first();
14755     },
14756     
14757     onTickableFooterButtonClick : function(e, btn, el)
14758     {
14759         e.preventDefault();
14760         
14761         this.lastItem = Roo.apply([], this.item);
14762         
14763         if(btn && btn.name == 'cancel'){
14764             this.tickItems = Roo.apply([], this.item);
14765             this.collapse();
14766             return;
14767         }
14768         
14769         this.clearItem();
14770         
14771         var _this = this;
14772         
14773         Roo.each(this.tickItems, function(o){
14774             _this.addItem(o);
14775         });
14776         
14777         this.collapse();
14778         
14779     },
14780     
14781     validate : function()
14782     {
14783         if(this.getVisibilityEl().hasClass('hidden')){
14784             return true;
14785         }
14786         
14787         var v = this.getRawValue();
14788         
14789         if(this.multiple){
14790             v = this.getValue();
14791         }
14792         
14793         if(this.disabled || this.allowBlank || v.length){
14794             this.markValid();
14795             return true;
14796         }
14797         
14798         this.markInvalid();
14799         return false;
14800     },
14801     
14802     tickableInputEl : function()
14803     {
14804         if(!this.tickable || !this.editable){
14805             return this.inputEl();
14806         }
14807         
14808         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14809     },
14810     
14811     
14812     getAutoCreateTouchView : function()
14813     {
14814         var id = Roo.id();
14815         
14816         var cfg = {
14817             cls: 'form-group' //input-group
14818         };
14819         
14820         var input =  {
14821             tag: 'input',
14822             id : id,
14823             type : this.inputType,
14824             cls : 'form-control x-combo-noedit',
14825             autocomplete: 'new-password',
14826             placeholder : this.placeholder || '',
14827             readonly : true
14828         };
14829         
14830         if (this.name) {
14831             input.name = this.name;
14832         }
14833         
14834         if (this.size) {
14835             input.cls += ' input-' + this.size;
14836         }
14837         
14838         if (this.disabled) {
14839             input.disabled = true;
14840         }
14841         
14842         var inputblock = {
14843             cls : '',
14844             cn : [
14845                 input
14846             ]
14847         };
14848         
14849         if(this.before){
14850             inputblock.cls += ' input-group';
14851             
14852             inputblock.cn.unshift({
14853                 tag :'span',
14854                 cls : 'input-group-addon',
14855                 html : this.before
14856             });
14857         }
14858         
14859         if(this.removable && !this.multiple){
14860             inputblock.cls += ' roo-removable';
14861             
14862             inputblock.cn.push({
14863                 tag: 'button',
14864                 html : 'x',
14865                 cls : 'roo-combo-removable-btn close'
14866             });
14867         }
14868
14869         if(this.hasFeedback && !this.allowBlank){
14870             
14871             inputblock.cls += ' has-feedback';
14872             
14873             inputblock.cn.push({
14874                 tag: 'span',
14875                 cls: 'glyphicon form-control-feedback'
14876             });
14877             
14878         }
14879         
14880         if (this.after) {
14881             
14882             inputblock.cls += (this.before) ? '' : ' input-group';
14883             
14884             inputblock.cn.push({
14885                 tag :'span',
14886                 cls : 'input-group-addon',
14887                 html : this.after
14888             });
14889         }
14890
14891         var box = {
14892             tag: 'div',
14893             cn: [
14894                 {
14895                     tag: 'input',
14896                     type : 'hidden',
14897                     cls: 'form-hidden-field'
14898                 },
14899                 inputblock
14900             ]
14901             
14902         };
14903         
14904         if(this.multiple){
14905             box = {
14906                 tag: 'div',
14907                 cn: [
14908                     {
14909                         tag: 'input',
14910                         type : 'hidden',
14911                         cls: 'form-hidden-field'
14912                     },
14913                     {
14914                         tag: 'ul',
14915                         cls: 'roo-select2-choices',
14916                         cn:[
14917                             {
14918                                 tag: 'li',
14919                                 cls: 'roo-select2-search-field',
14920                                 cn: [
14921
14922                                     inputblock
14923                                 ]
14924                             }
14925                         ]
14926                     }
14927                 ]
14928             }
14929         };
14930         
14931         var combobox = {
14932             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14933             cn: [
14934                 box
14935             ]
14936         };
14937         
14938         if(!this.multiple && this.showToggleBtn){
14939             
14940             var caret = {
14941                         tag: 'span',
14942                         cls: 'caret'
14943             };
14944             
14945             if (this.caret != false) {
14946                 caret = {
14947                      tag: 'i',
14948                      cls: 'fa fa-' + this.caret
14949                 };
14950                 
14951             }
14952             
14953             combobox.cn.push({
14954                 tag :'span',
14955                 cls : 'input-group-addon btn dropdown-toggle',
14956                 cn : [
14957                     caret,
14958                     {
14959                         tag: 'span',
14960                         cls: 'combobox-clear',
14961                         cn  : [
14962                             {
14963                                 tag : 'i',
14964                                 cls: 'icon-remove'
14965                             }
14966                         ]
14967                     }
14968                 ]
14969
14970             })
14971         }
14972         
14973         if(this.multiple){
14974             combobox.cls += ' roo-select2-container-multi';
14975         }
14976         
14977         var align = this.labelAlign || this.parentLabelAlign();
14978         
14979         if (align ==='left' && this.fieldLabel.length) {
14980
14981             cfg.cn = [
14982                 {
14983                    tag : 'i',
14984                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14985                    tooltip : 'This field is required'
14986                 },
14987                 {
14988                     tag: 'label',
14989                     cls : 'control-label',
14990                     html : this.fieldLabel
14991
14992                 },
14993                 {
14994                     cls : '', 
14995                     cn: [
14996                         combobox
14997                     ]
14998                 }
14999             ];
15000             
15001             var labelCfg = cfg.cn[1];
15002             var contentCfg = cfg.cn[2];
15003             
15004
15005             if(this.indicatorpos == 'right'){
15006                 cfg.cn = [
15007                     {
15008                         tag: 'label',
15009                         'for' :  id,
15010                         cls : 'control-label',
15011                         cn : [
15012                             {
15013                                 tag : 'span',
15014                                 html : this.fieldLabel
15015                             },
15016                             {
15017                                 tag : 'i',
15018                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15019                                 tooltip : 'This field is required'
15020                             }
15021                         ]
15022                     },
15023                     {
15024                         cls : "",
15025                         cn: [
15026                             combobox
15027                         ]
15028                     }
15029
15030                 ];
15031                 
15032                 labelCfg = cfg.cn[0];
15033                 contentCfg = cfg.cn[1];
15034             }
15035             
15036            
15037             
15038             if(this.labelWidth > 12){
15039                 labelCfg.style = "width: " + this.labelWidth + 'px';
15040             }
15041             
15042             if(this.labelWidth < 13 && this.labelmd == 0){
15043                 this.labelmd = this.labelWidth;
15044             }
15045             
15046             if(this.labellg > 0){
15047                 labelCfg.cls += ' col-lg-' + this.labellg;
15048                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15049             }
15050             
15051             if(this.labelmd > 0){
15052                 labelCfg.cls += ' col-md-' + this.labelmd;
15053                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15054             }
15055             
15056             if(this.labelsm > 0){
15057                 labelCfg.cls += ' col-sm-' + this.labelsm;
15058                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15059             }
15060             
15061             if(this.labelxs > 0){
15062                 labelCfg.cls += ' col-xs-' + this.labelxs;
15063                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15064             }
15065                 
15066                 
15067         } else if ( this.fieldLabel.length) {
15068             cfg.cn = [
15069                 {
15070                    tag : 'i',
15071                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15072                    tooltip : 'This field is required'
15073                 },
15074                 {
15075                     tag: 'label',
15076                     cls : 'control-label',
15077                     html : this.fieldLabel
15078
15079                 },
15080                 {
15081                     cls : '', 
15082                     cn: [
15083                         combobox
15084                     ]
15085                 }
15086             ];
15087             
15088             if(this.indicatorpos == 'right'){
15089                 cfg.cn = [
15090                     {
15091                         tag: 'label',
15092                         cls : 'control-label',
15093                         html : this.fieldLabel,
15094                         cn : [
15095                             {
15096                                tag : 'i',
15097                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15098                                tooltip : 'This field is required'
15099                             }
15100                         ]
15101                     },
15102                     {
15103                         cls : '', 
15104                         cn: [
15105                             combobox
15106                         ]
15107                     }
15108                 ];
15109             }
15110         } else {
15111             cfg.cn = combobox;    
15112         }
15113         
15114         
15115         var settings = this;
15116         
15117         ['xs','sm','md','lg'].map(function(size){
15118             if (settings[size]) {
15119                 cfg.cls += ' col-' + size + '-' + settings[size];
15120             }
15121         });
15122         
15123         return cfg;
15124     },
15125     
15126     initTouchView : function()
15127     {
15128         this.renderTouchView();
15129         
15130         this.touchViewEl.on('scroll', function(){
15131             this.el.dom.scrollTop = 0;
15132         }, this);
15133         
15134         this.originalValue = this.getValue();
15135         
15136         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15137         
15138         this.inputEl().on("click", this.showTouchView, this);
15139         if (this.triggerEl) {
15140             this.triggerEl.on("click", this.showTouchView, this);
15141         }
15142         
15143         
15144         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15145         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15146         
15147         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15148         
15149         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15150         this.store.on('load', this.onTouchViewLoad, this);
15151         this.store.on('loadexception', this.onTouchViewLoadException, this);
15152         
15153         if(this.hiddenName){
15154             
15155             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15156             
15157             this.hiddenField.dom.value =
15158                 this.hiddenValue !== undefined ? this.hiddenValue :
15159                 this.value !== undefined ? this.value : '';
15160         
15161             this.el.dom.removeAttribute('name');
15162             this.hiddenField.dom.setAttribute('name', this.hiddenName);
15163         }
15164         
15165         if(this.multiple){
15166             this.choices = this.el.select('ul.roo-select2-choices', true).first();
15167             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15168         }
15169         
15170         if(this.removable && !this.multiple){
15171             var close = this.closeTriggerEl();
15172             if(close){
15173                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15174                 close.on('click', this.removeBtnClick, this, close);
15175             }
15176         }
15177         /*
15178          * fix the bug in Safari iOS8
15179          */
15180         this.inputEl().on("focus", function(e){
15181             document.activeElement.blur();
15182         }, this);
15183         
15184         return;
15185         
15186         
15187     },
15188     
15189     renderTouchView : function()
15190     {
15191         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15192         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15193         
15194         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15195         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15196         
15197         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15198         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15199         this.touchViewBodyEl.setStyle('overflow', 'auto');
15200         
15201         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15202         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15203         
15204         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15205         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15206         
15207     },
15208     
15209     showTouchView : function()
15210     {
15211         if(this.disabled){
15212             return;
15213         }
15214         
15215         this.touchViewHeaderEl.hide();
15216
15217         if(this.modalTitle.length){
15218             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15219             this.touchViewHeaderEl.show();
15220         }
15221
15222         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15223         this.touchViewEl.show();
15224
15225         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15226         
15227         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15228         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15229
15230         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15231
15232         if(this.modalTitle.length){
15233             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15234         }
15235         
15236         this.touchViewBodyEl.setHeight(bodyHeight);
15237
15238         if(this.animate){
15239             var _this = this;
15240             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15241         }else{
15242             this.touchViewEl.addClass('in');
15243         }
15244
15245         this.doTouchViewQuery();
15246         
15247     },
15248     
15249     hideTouchView : function()
15250     {
15251         this.touchViewEl.removeClass('in');
15252
15253         if(this.animate){
15254             var _this = this;
15255             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15256         }else{
15257             this.touchViewEl.setStyle('display', 'none');
15258         }
15259         
15260     },
15261     
15262     setTouchViewValue : function()
15263     {
15264         if(this.multiple){
15265             this.clearItem();
15266         
15267             var _this = this;
15268
15269             Roo.each(this.tickItems, function(o){
15270                 this.addItem(o);
15271             }, this);
15272         }
15273         
15274         this.hideTouchView();
15275     },
15276     
15277     doTouchViewQuery : function()
15278     {
15279         var qe = {
15280             query: '',
15281             forceAll: true,
15282             combo: this,
15283             cancel:false
15284         };
15285         
15286         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15287             return false;
15288         }
15289         
15290         if(!this.alwaysQuery || this.mode == 'local'){
15291             this.onTouchViewLoad();
15292             return;
15293         }
15294         
15295         this.store.load();
15296     },
15297     
15298     onTouchViewBeforeLoad : function(combo,opts)
15299     {
15300         return;
15301     },
15302
15303     // private
15304     onTouchViewLoad : function()
15305     {
15306         if(this.store.getCount() < 1){
15307             this.onTouchViewEmptyResults();
15308             return;
15309         }
15310         
15311         this.clearTouchView();
15312         
15313         var rawValue = this.getRawValue();
15314         
15315         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15316         
15317         this.tickItems = [];
15318         
15319         this.store.data.each(function(d, rowIndex){
15320             var row = this.touchViewListGroup.createChild(template);
15321             
15322             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15323                 row.addClass(d.data.cls);
15324             }
15325             
15326             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15327                 var cfg = {
15328                     data : d.data,
15329                     html : d.data[this.displayField]
15330                 };
15331                 
15332                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15333                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15334                 }
15335             }
15336             row.removeClass('selected');
15337             if(!this.multiple && this.valueField &&
15338                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15339             {
15340                 // radio buttons..
15341                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15342                 row.addClass('selected');
15343             }
15344             
15345             if(this.multiple && this.valueField &&
15346                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15347             {
15348                 
15349                 // checkboxes...
15350                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15351                 this.tickItems.push(d.data);
15352             }
15353             
15354             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15355             
15356         }, this);
15357         
15358         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15359         
15360         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15361
15362         if(this.modalTitle.length){
15363             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15364         }
15365
15366         var listHeight = this.touchViewListGroup.getHeight();
15367         
15368         var _this = this;
15369         
15370         if(firstChecked && listHeight > bodyHeight){
15371             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15372         }
15373         
15374     },
15375     
15376     onTouchViewLoadException : function()
15377     {
15378         this.hideTouchView();
15379     },
15380     
15381     onTouchViewEmptyResults : function()
15382     {
15383         this.clearTouchView();
15384         
15385         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15386         
15387         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15388         
15389     },
15390     
15391     clearTouchView : function()
15392     {
15393         this.touchViewListGroup.dom.innerHTML = '';
15394     },
15395     
15396     onTouchViewClick : function(e, el, o)
15397     {
15398         e.preventDefault();
15399         
15400         var row = o.row;
15401         var rowIndex = o.rowIndex;
15402         
15403         var r = this.store.getAt(rowIndex);
15404         
15405         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15406             
15407             if(!this.multiple){
15408                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15409                     c.dom.removeAttribute('checked');
15410                 }, this);
15411
15412                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15413
15414                 this.setFromData(r.data);
15415
15416                 var close = this.closeTriggerEl();
15417
15418                 if(close){
15419                     close.show();
15420                 }
15421
15422                 this.hideTouchView();
15423
15424                 this.fireEvent('select', this, r, rowIndex);
15425
15426                 return;
15427             }
15428
15429             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15430                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15431                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15432                 return;
15433             }
15434
15435             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15436             this.addItem(r.data);
15437             this.tickItems.push(r.data);
15438         }
15439     },
15440     
15441     getAutoCreateNativeIOS : function()
15442     {
15443         var cfg = {
15444             cls: 'form-group' //input-group,
15445         };
15446         
15447         var combobox =  {
15448             tag: 'select',
15449             cls : 'roo-ios-select'
15450         };
15451         
15452         if (this.name) {
15453             combobox.name = this.name;
15454         }
15455         
15456         if (this.disabled) {
15457             combobox.disabled = true;
15458         }
15459         
15460         var settings = this;
15461         
15462         ['xs','sm','md','lg'].map(function(size){
15463             if (settings[size]) {
15464                 cfg.cls += ' col-' + size + '-' + settings[size];
15465             }
15466         });
15467         
15468         cfg.cn = combobox;
15469         
15470         return cfg;
15471         
15472     },
15473     
15474     initIOSView : function()
15475     {
15476         this.store.on('load', this.onIOSViewLoad, this);
15477         
15478         return;
15479     },
15480     
15481     onIOSViewLoad : function()
15482     {
15483         if(this.store.getCount() < 1){
15484             return;
15485         }
15486         
15487         this.clearIOSView();
15488         
15489         if(this.allowBlank) {
15490             
15491             var default_text = '-- SELECT --';
15492             
15493             if(this.placeholder.length){
15494                 default_text = this.placeholder;
15495             }
15496             
15497             if(this.emptyTitle.length){
15498                 default_text += ' - ' + this.emptyTitle + ' -';
15499             }
15500             
15501             var opt = this.inputEl().createChild({
15502                 tag: 'option',
15503                 value : 0,
15504                 html : default_text
15505             });
15506             
15507             var o = {};
15508             o[this.valueField] = 0;
15509             o[this.displayField] = default_text;
15510             
15511             this.ios_options.push({
15512                 data : o,
15513                 el : opt
15514             });
15515             
15516         }
15517         
15518         this.store.data.each(function(d, rowIndex){
15519             
15520             var html = '';
15521             
15522             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15523                 html = d.data[this.displayField];
15524             }
15525             
15526             var value = '';
15527             
15528             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15529                 value = d.data[this.valueField];
15530             }
15531             
15532             var option = {
15533                 tag: 'option',
15534                 value : value,
15535                 html : html
15536             };
15537             
15538             if(this.value == d.data[this.valueField]){
15539                 option['selected'] = true;
15540             }
15541             
15542             var opt = this.inputEl().createChild(option);
15543             
15544             this.ios_options.push({
15545                 data : d.data,
15546                 el : opt
15547             });
15548             
15549         }, this);
15550         
15551         this.inputEl().on('change', function(){
15552            this.fireEvent('select', this);
15553         }, this);
15554         
15555     },
15556     
15557     clearIOSView: function()
15558     {
15559         this.inputEl().dom.innerHTML = '';
15560         
15561         this.ios_options = [];
15562     },
15563     
15564     setIOSValue: function(v)
15565     {
15566         this.value = v;
15567         
15568         if(!this.ios_options){
15569             return;
15570         }
15571         
15572         Roo.each(this.ios_options, function(opts){
15573            
15574            opts.el.dom.removeAttribute('selected');
15575            
15576            if(opts.data[this.valueField] != v){
15577                return;
15578            }
15579            
15580            opts.el.dom.setAttribute('selected', true);
15581            
15582         }, this);
15583     }
15584
15585     /** 
15586     * @cfg {Boolean} grow 
15587     * @hide 
15588     */
15589     /** 
15590     * @cfg {Number} growMin 
15591     * @hide 
15592     */
15593     /** 
15594     * @cfg {Number} growMax 
15595     * @hide 
15596     */
15597     /**
15598      * @hide
15599      * @method autoSize
15600      */
15601 });
15602
15603 Roo.apply(Roo.bootstrap.ComboBox,  {
15604     
15605     header : {
15606         tag: 'div',
15607         cls: 'modal-header',
15608         cn: [
15609             {
15610                 tag: 'h4',
15611                 cls: 'modal-title'
15612             }
15613         ]
15614     },
15615     
15616     body : {
15617         tag: 'div',
15618         cls: 'modal-body',
15619         cn: [
15620             {
15621                 tag: 'ul',
15622                 cls: 'list-group'
15623             }
15624         ]
15625     },
15626     
15627     listItemRadio : {
15628         tag: 'li',
15629         cls: 'list-group-item',
15630         cn: [
15631             {
15632                 tag: 'span',
15633                 cls: 'roo-combobox-list-group-item-value'
15634             },
15635             {
15636                 tag: 'div',
15637                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15638                 cn: [
15639                     {
15640                         tag: 'input',
15641                         type: 'radio'
15642                     },
15643                     {
15644                         tag: 'label'
15645                     }
15646                 ]
15647             }
15648         ]
15649     },
15650     
15651     listItemCheckbox : {
15652         tag: 'li',
15653         cls: 'list-group-item',
15654         cn: [
15655             {
15656                 tag: 'span',
15657                 cls: 'roo-combobox-list-group-item-value'
15658             },
15659             {
15660                 tag: 'div',
15661                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15662                 cn: [
15663                     {
15664                         tag: 'input',
15665                         type: 'checkbox'
15666                     },
15667                     {
15668                         tag: 'label'
15669                     }
15670                 ]
15671             }
15672         ]
15673     },
15674     
15675     emptyResult : {
15676         tag: 'div',
15677         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15678     },
15679     
15680     footer : {
15681         tag: 'div',
15682         cls: 'modal-footer',
15683         cn: [
15684             {
15685                 tag: 'div',
15686                 cls: 'row',
15687                 cn: [
15688                     {
15689                         tag: 'div',
15690                         cls: 'col-xs-6 text-left',
15691                         cn: {
15692                             tag: 'button',
15693                             cls: 'btn btn-danger roo-touch-view-cancel',
15694                             html: 'Cancel'
15695                         }
15696                     },
15697                     {
15698                         tag: 'div',
15699                         cls: 'col-xs-6 text-right',
15700                         cn: {
15701                             tag: 'button',
15702                             cls: 'btn btn-success roo-touch-view-ok',
15703                             html: 'OK'
15704                         }
15705                     }
15706                 ]
15707             }
15708         ]
15709         
15710     }
15711 });
15712
15713 Roo.apply(Roo.bootstrap.ComboBox,  {
15714     
15715     touchViewTemplate : {
15716         tag: 'div',
15717         cls: 'modal fade roo-combobox-touch-view',
15718         cn: [
15719             {
15720                 tag: 'div',
15721                 cls: 'modal-dialog',
15722                 style : 'position:fixed', // we have to fix position....
15723                 cn: [
15724                     {
15725                         tag: 'div',
15726                         cls: 'modal-content',
15727                         cn: [
15728                             Roo.bootstrap.ComboBox.header,
15729                             Roo.bootstrap.ComboBox.body,
15730                             Roo.bootstrap.ComboBox.footer
15731                         ]
15732                     }
15733                 ]
15734             }
15735         ]
15736     }
15737 });/*
15738  * Based on:
15739  * Ext JS Library 1.1.1
15740  * Copyright(c) 2006-2007, Ext JS, LLC.
15741  *
15742  * Originally Released Under LGPL - original licence link has changed is not relivant.
15743  *
15744  * Fork - LGPL
15745  * <script type="text/javascript">
15746  */
15747
15748 /**
15749  * @class Roo.View
15750  * @extends Roo.util.Observable
15751  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15752  * This class also supports single and multi selection modes. <br>
15753  * Create a data model bound view:
15754  <pre><code>
15755  var store = new Roo.data.Store(...);
15756
15757  var view = new Roo.View({
15758     el : "my-element",
15759     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15760  
15761     singleSelect: true,
15762     selectedClass: "ydataview-selected",
15763     store: store
15764  });
15765
15766  // listen for node click?
15767  view.on("click", function(vw, index, node, e){
15768  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15769  });
15770
15771  // load XML data
15772  dataModel.load("foobar.xml");
15773  </code></pre>
15774  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15775  * <br><br>
15776  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15777  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15778  * 
15779  * Note: old style constructor is still suported (container, template, config)
15780  * 
15781  * @constructor
15782  * Create a new View
15783  * @param {Object} config The config object
15784  * 
15785  */
15786 Roo.View = function(config, depreciated_tpl, depreciated_config){
15787     
15788     this.parent = false;
15789     
15790     if (typeof(depreciated_tpl) == 'undefined') {
15791         // new way.. - universal constructor.
15792         Roo.apply(this, config);
15793         this.el  = Roo.get(this.el);
15794     } else {
15795         // old format..
15796         this.el  = Roo.get(config);
15797         this.tpl = depreciated_tpl;
15798         Roo.apply(this, depreciated_config);
15799     }
15800     this.wrapEl  = this.el.wrap().wrap();
15801     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15802     
15803     
15804     if(typeof(this.tpl) == "string"){
15805         this.tpl = new Roo.Template(this.tpl);
15806     } else {
15807         // support xtype ctors..
15808         this.tpl = new Roo.factory(this.tpl, Roo);
15809     }
15810     
15811     
15812     this.tpl.compile();
15813     
15814     /** @private */
15815     this.addEvents({
15816         /**
15817          * @event beforeclick
15818          * Fires before a click is processed. Returns false to cancel the default action.
15819          * @param {Roo.View} this
15820          * @param {Number} index The index of the target node
15821          * @param {HTMLElement} node The target node
15822          * @param {Roo.EventObject} e The raw event object
15823          */
15824             "beforeclick" : true,
15825         /**
15826          * @event click
15827          * Fires when a template node is clicked.
15828          * @param {Roo.View} this
15829          * @param {Number} index The index of the target node
15830          * @param {HTMLElement} node The target node
15831          * @param {Roo.EventObject} e The raw event object
15832          */
15833             "click" : true,
15834         /**
15835          * @event dblclick
15836          * Fires when a template node is double clicked.
15837          * @param {Roo.View} this
15838          * @param {Number} index The index of the target node
15839          * @param {HTMLElement} node The target node
15840          * @param {Roo.EventObject} e The raw event object
15841          */
15842             "dblclick" : true,
15843         /**
15844          * @event contextmenu
15845          * Fires when a template node is right clicked.
15846          * @param {Roo.View} this
15847          * @param {Number} index The index of the target node
15848          * @param {HTMLElement} node The target node
15849          * @param {Roo.EventObject} e The raw event object
15850          */
15851             "contextmenu" : true,
15852         /**
15853          * @event selectionchange
15854          * Fires when the selected nodes change.
15855          * @param {Roo.View} this
15856          * @param {Array} selections Array of the selected nodes
15857          */
15858             "selectionchange" : true,
15859     
15860         /**
15861          * @event beforeselect
15862          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15863          * @param {Roo.View} this
15864          * @param {HTMLElement} node The node to be selected
15865          * @param {Array} selections Array of currently selected nodes
15866          */
15867             "beforeselect" : true,
15868         /**
15869          * @event preparedata
15870          * Fires on every row to render, to allow you to change the data.
15871          * @param {Roo.View} this
15872          * @param {Object} data to be rendered (change this)
15873          */
15874           "preparedata" : true
15875           
15876           
15877         });
15878
15879
15880
15881     this.el.on({
15882         "click": this.onClick,
15883         "dblclick": this.onDblClick,
15884         "contextmenu": this.onContextMenu,
15885         scope:this
15886     });
15887
15888     this.selections = [];
15889     this.nodes = [];
15890     this.cmp = new Roo.CompositeElementLite([]);
15891     if(this.store){
15892         this.store = Roo.factory(this.store, Roo.data);
15893         this.setStore(this.store, true);
15894     }
15895     
15896     if ( this.footer && this.footer.xtype) {
15897            
15898          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15899         
15900         this.footer.dataSource = this.store;
15901         this.footer.container = fctr;
15902         this.footer = Roo.factory(this.footer, Roo);
15903         fctr.insertFirst(this.el);
15904         
15905         // this is a bit insane - as the paging toolbar seems to detach the el..
15906 //        dom.parentNode.parentNode.parentNode
15907          // they get detached?
15908     }
15909     
15910     
15911     Roo.View.superclass.constructor.call(this);
15912     
15913     
15914 };
15915
15916 Roo.extend(Roo.View, Roo.util.Observable, {
15917     
15918      /**
15919      * @cfg {Roo.data.Store} store Data store to load data from.
15920      */
15921     store : false,
15922     
15923     /**
15924      * @cfg {String|Roo.Element} el The container element.
15925      */
15926     el : '',
15927     
15928     /**
15929      * @cfg {String|Roo.Template} tpl The template used by this View 
15930      */
15931     tpl : false,
15932     /**
15933      * @cfg {String} dataName the named area of the template to use as the data area
15934      *                          Works with domtemplates roo-name="name"
15935      */
15936     dataName: false,
15937     /**
15938      * @cfg {String} selectedClass The css class to add to selected nodes
15939      */
15940     selectedClass : "x-view-selected",
15941      /**
15942      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15943      */
15944     emptyText : "",
15945     
15946     /**
15947      * @cfg {String} text to display on mask (default Loading)
15948      */
15949     mask : false,
15950     /**
15951      * @cfg {Boolean} multiSelect Allow multiple selection
15952      */
15953     multiSelect : false,
15954     /**
15955      * @cfg {Boolean} singleSelect Allow single selection
15956      */
15957     singleSelect:  false,
15958     
15959     /**
15960      * @cfg {Boolean} toggleSelect - selecting 
15961      */
15962     toggleSelect : false,
15963     
15964     /**
15965      * @cfg {Boolean} tickable - selecting 
15966      */
15967     tickable : false,
15968     
15969     /**
15970      * Returns the element this view is bound to.
15971      * @return {Roo.Element}
15972      */
15973     getEl : function(){
15974         return this.wrapEl;
15975     },
15976     
15977     
15978
15979     /**
15980      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15981      */
15982     refresh : function(){
15983         //Roo.log('refresh');
15984         var t = this.tpl;
15985         
15986         // if we are using something like 'domtemplate', then
15987         // the what gets used is:
15988         // t.applySubtemplate(NAME, data, wrapping data..)
15989         // the outer template then get' applied with
15990         //     the store 'extra data'
15991         // and the body get's added to the
15992         //      roo-name="data" node?
15993         //      <span class='roo-tpl-{name}'></span> ?????
15994         
15995         
15996         
15997         this.clearSelections();
15998         this.el.update("");
15999         var html = [];
16000         var records = this.store.getRange();
16001         if(records.length < 1) {
16002             
16003             // is this valid??  = should it render a template??
16004             
16005             this.el.update(this.emptyText);
16006             return;
16007         }
16008         var el = this.el;
16009         if (this.dataName) {
16010             this.el.update(t.apply(this.store.meta)); //????
16011             el = this.el.child('.roo-tpl-' + this.dataName);
16012         }
16013         
16014         for(var i = 0, len = records.length; i < len; i++){
16015             var data = this.prepareData(records[i].data, i, records[i]);
16016             this.fireEvent("preparedata", this, data, i, records[i]);
16017             
16018             var d = Roo.apply({}, data);
16019             
16020             if(this.tickable){
16021                 Roo.apply(d, {'roo-id' : Roo.id()});
16022                 
16023                 var _this = this;
16024             
16025                 Roo.each(this.parent.item, function(item){
16026                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16027                         return;
16028                     }
16029                     Roo.apply(d, {'roo-data-checked' : 'checked'});
16030                 });
16031             }
16032             
16033             html[html.length] = Roo.util.Format.trim(
16034                 this.dataName ?
16035                     t.applySubtemplate(this.dataName, d, this.store.meta) :
16036                     t.apply(d)
16037             );
16038         }
16039         
16040         
16041         
16042         el.update(html.join(""));
16043         this.nodes = el.dom.childNodes;
16044         this.updateIndexes(0);
16045     },
16046     
16047
16048     /**
16049      * Function to override to reformat the data that is sent to
16050      * the template for each node.
16051      * DEPRICATED - use the preparedata event handler.
16052      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16053      * a JSON object for an UpdateManager bound view).
16054      */
16055     prepareData : function(data, index, record)
16056     {
16057         this.fireEvent("preparedata", this, data, index, record);
16058         return data;
16059     },
16060
16061     onUpdate : function(ds, record){
16062         // Roo.log('on update');   
16063         this.clearSelections();
16064         var index = this.store.indexOf(record);
16065         var n = this.nodes[index];
16066         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16067         n.parentNode.removeChild(n);
16068         this.updateIndexes(index, index);
16069     },
16070
16071     
16072     
16073 // --------- FIXME     
16074     onAdd : function(ds, records, index)
16075     {
16076         //Roo.log(['on Add', ds, records, index] );        
16077         this.clearSelections();
16078         if(this.nodes.length == 0){
16079             this.refresh();
16080             return;
16081         }
16082         var n = this.nodes[index];
16083         for(var i = 0, len = records.length; i < len; i++){
16084             var d = this.prepareData(records[i].data, i, records[i]);
16085             if(n){
16086                 this.tpl.insertBefore(n, d);
16087             }else{
16088                 
16089                 this.tpl.append(this.el, d);
16090             }
16091         }
16092         this.updateIndexes(index);
16093     },
16094
16095     onRemove : function(ds, record, index){
16096        // Roo.log('onRemove');
16097         this.clearSelections();
16098         var el = this.dataName  ?
16099             this.el.child('.roo-tpl-' + this.dataName) :
16100             this.el; 
16101         
16102         el.dom.removeChild(this.nodes[index]);
16103         this.updateIndexes(index);
16104     },
16105
16106     /**
16107      * Refresh an individual node.
16108      * @param {Number} index
16109      */
16110     refreshNode : function(index){
16111         this.onUpdate(this.store, this.store.getAt(index));
16112     },
16113
16114     updateIndexes : function(startIndex, endIndex){
16115         var ns = this.nodes;
16116         startIndex = startIndex || 0;
16117         endIndex = endIndex || ns.length - 1;
16118         for(var i = startIndex; i <= endIndex; i++){
16119             ns[i].nodeIndex = i;
16120         }
16121     },
16122
16123     /**
16124      * Changes the data store this view uses and refresh the view.
16125      * @param {Store} store
16126      */
16127     setStore : function(store, initial){
16128         if(!initial && this.store){
16129             this.store.un("datachanged", this.refresh);
16130             this.store.un("add", this.onAdd);
16131             this.store.un("remove", this.onRemove);
16132             this.store.un("update", this.onUpdate);
16133             this.store.un("clear", this.refresh);
16134             this.store.un("beforeload", this.onBeforeLoad);
16135             this.store.un("load", this.onLoad);
16136             this.store.un("loadexception", this.onLoad);
16137         }
16138         if(store){
16139           
16140             store.on("datachanged", this.refresh, this);
16141             store.on("add", this.onAdd, this);
16142             store.on("remove", this.onRemove, this);
16143             store.on("update", this.onUpdate, this);
16144             store.on("clear", this.refresh, this);
16145             store.on("beforeload", this.onBeforeLoad, this);
16146             store.on("load", this.onLoad, this);
16147             store.on("loadexception", this.onLoad, this);
16148         }
16149         
16150         if(store){
16151             this.refresh();
16152         }
16153     },
16154     /**
16155      * onbeforeLoad - masks the loading area.
16156      *
16157      */
16158     onBeforeLoad : function(store,opts)
16159     {
16160          //Roo.log('onBeforeLoad');   
16161         if (!opts.add) {
16162             this.el.update("");
16163         }
16164         this.el.mask(this.mask ? this.mask : "Loading" ); 
16165     },
16166     onLoad : function ()
16167     {
16168         this.el.unmask();
16169     },
16170     
16171
16172     /**
16173      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16174      * @param {HTMLElement} node
16175      * @return {HTMLElement} The template node
16176      */
16177     findItemFromChild : function(node){
16178         var el = this.dataName  ?
16179             this.el.child('.roo-tpl-' + this.dataName,true) :
16180             this.el.dom; 
16181         
16182         if(!node || node.parentNode == el){
16183                     return node;
16184             }
16185             var p = node.parentNode;
16186             while(p && p != el){
16187             if(p.parentNode == el){
16188                 return p;
16189             }
16190             p = p.parentNode;
16191         }
16192             return null;
16193     },
16194
16195     /** @ignore */
16196     onClick : function(e){
16197         var item = this.findItemFromChild(e.getTarget());
16198         if(item){
16199             var index = this.indexOf(item);
16200             if(this.onItemClick(item, index, e) !== false){
16201                 this.fireEvent("click", this, index, item, e);
16202             }
16203         }else{
16204             this.clearSelections();
16205         }
16206     },
16207
16208     /** @ignore */
16209     onContextMenu : function(e){
16210         var item = this.findItemFromChild(e.getTarget());
16211         if(item){
16212             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16213         }
16214     },
16215
16216     /** @ignore */
16217     onDblClick : function(e){
16218         var item = this.findItemFromChild(e.getTarget());
16219         if(item){
16220             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16221         }
16222     },
16223
16224     onItemClick : function(item, index, e)
16225     {
16226         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16227             return false;
16228         }
16229         if (this.toggleSelect) {
16230             var m = this.isSelected(item) ? 'unselect' : 'select';
16231             //Roo.log(m);
16232             var _t = this;
16233             _t[m](item, true, false);
16234             return true;
16235         }
16236         if(this.multiSelect || this.singleSelect){
16237             if(this.multiSelect && e.shiftKey && this.lastSelection){
16238                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16239             }else{
16240                 this.select(item, this.multiSelect && e.ctrlKey);
16241                 this.lastSelection = item;
16242             }
16243             
16244             if(!this.tickable){
16245                 e.preventDefault();
16246             }
16247             
16248         }
16249         return true;
16250     },
16251
16252     /**
16253      * Get the number of selected nodes.
16254      * @return {Number}
16255      */
16256     getSelectionCount : function(){
16257         return this.selections.length;
16258     },
16259
16260     /**
16261      * Get the currently selected nodes.
16262      * @return {Array} An array of HTMLElements
16263      */
16264     getSelectedNodes : function(){
16265         return this.selections;
16266     },
16267
16268     /**
16269      * Get the indexes of the selected nodes.
16270      * @return {Array}
16271      */
16272     getSelectedIndexes : function(){
16273         var indexes = [], s = this.selections;
16274         for(var i = 0, len = s.length; i < len; i++){
16275             indexes.push(s[i].nodeIndex);
16276         }
16277         return indexes;
16278     },
16279
16280     /**
16281      * Clear all selections
16282      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16283      */
16284     clearSelections : function(suppressEvent){
16285         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16286             this.cmp.elements = this.selections;
16287             this.cmp.removeClass(this.selectedClass);
16288             this.selections = [];
16289             if(!suppressEvent){
16290                 this.fireEvent("selectionchange", this, this.selections);
16291             }
16292         }
16293     },
16294
16295     /**
16296      * Returns true if the passed node is selected
16297      * @param {HTMLElement/Number} node The node or node index
16298      * @return {Boolean}
16299      */
16300     isSelected : function(node){
16301         var s = this.selections;
16302         if(s.length < 1){
16303             return false;
16304         }
16305         node = this.getNode(node);
16306         return s.indexOf(node) !== -1;
16307     },
16308
16309     /**
16310      * Selects nodes.
16311      * @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
16312      * @param {Boolean} keepExisting (optional) true to keep existing selections
16313      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16314      */
16315     select : function(nodeInfo, keepExisting, suppressEvent){
16316         if(nodeInfo instanceof Array){
16317             if(!keepExisting){
16318                 this.clearSelections(true);
16319             }
16320             for(var i = 0, len = nodeInfo.length; i < len; i++){
16321                 this.select(nodeInfo[i], true, true);
16322             }
16323             return;
16324         } 
16325         var node = this.getNode(nodeInfo);
16326         if(!node || this.isSelected(node)){
16327             return; // already selected.
16328         }
16329         if(!keepExisting){
16330             this.clearSelections(true);
16331         }
16332         
16333         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16334             Roo.fly(node).addClass(this.selectedClass);
16335             this.selections.push(node);
16336             if(!suppressEvent){
16337                 this.fireEvent("selectionchange", this, this.selections);
16338             }
16339         }
16340         
16341         
16342     },
16343       /**
16344      * Unselects nodes.
16345      * @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
16346      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16347      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16348      */
16349     unselect : function(nodeInfo, keepExisting, suppressEvent)
16350     {
16351         if(nodeInfo instanceof Array){
16352             Roo.each(this.selections, function(s) {
16353                 this.unselect(s, nodeInfo);
16354             }, this);
16355             return;
16356         }
16357         var node = this.getNode(nodeInfo);
16358         if(!node || !this.isSelected(node)){
16359             //Roo.log("not selected");
16360             return; // not selected.
16361         }
16362         // fireevent???
16363         var ns = [];
16364         Roo.each(this.selections, function(s) {
16365             if (s == node ) {
16366                 Roo.fly(node).removeClass(this.selectedClass);
16367
16368                 return;
16369             }
16370             ns.push(s);
16371         },this);
16372         
16373         this.selections= ns;
16374         this.fireEvent("selectionchange", this, this.selections);
16375     },
16376
16377     /**
16378      * Gets a template node.
16379      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16380      * @return {HTMLElement} The node or null if it wasn't found
16381      */
16382     getNode : function(nodeInfo){
16383         if(typeof nodeInfo == "string"){
16384             return document.getElementById(nodeInfo);
16385         }else if(typeof nodeInfo == "number"){
16386             return this.nodes[nodeInfo];
16387         }
16388         return nodeInfo;
16389     },
16390
16391     /**
16392      * Gets a range template nodes.
16393      * @param {Number} startIndex
16394      * @param {Number} endIndex
16395      * @return {Array} An array of nodes
16396      */
16397     getNodes : function(start, end){
16398         var ns = this.nodes;
16399         start = start || 0;
16400         end = typeof end == "undefined" ? ns.length - 1 : end;
16401         var nodes = [];
16402         if(start <= end){
16403             for(var i = start; i <= end; i++){
16404                 nodes.push(ns[i]);
16405             }
16406         } else{
16407             for(var i = start; i >= end; i--){
16408                 nodes.push(ns[i]);
16409             }
16410         }
16411         return nodes;
16412     },
16413
16414     /**
16415      * Finds the index of the passed node
16416      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16417      * @return {Number} The index of the node or -1
16418      */
16419     indexOf : function(node){
16420         node = this.getNode(node);
16421         if(typeof node.nodeIndex == "number"){
16422             return node.nodeIndex;
16423         }
16424         var ns = this.nodes;
16425         for(var i = 0, len = ns.length; i < len; i++){
16426             if(ns[i] == node){
16427                 return i;
16428             }
16429         }
16430         return -1;
16431     }
16432 });
16433 /*
16434  * - LGPL
16435  *
16436  * based on jquery fullcalendar
16437  * 
16438  */
16439
16440 Roo.bootstrap = Roo.bootstrap || {};
16441 /**
16442  * @class Roo.bootstrap.Calendar
16443  * @extends Roo.bootstrap.Component
16444  * Bootstrap Calendar class
16445  * @cfg {Boolean} loadMask (true|false) default false
16446  * @cfg {Object} header generate the user specific header of the calendar, default false
16447
16448  * @constructor
16449  * Create a new Container
16450  * @param {Object} config The config object
16451  */
16452
16453
16454
16455 Roo.bootstrap.Calendar = function(config){
16456     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16457      this.addEvents({
16458         /**
16459              * @event select
16460              * Fires when a date is selected
16461              * @param {DatePicker} this
16462              * @param {Date} date The selected date
16463              */
16464         'select': true,
16465         /**
16466              * @event monthchange
16467              * Fires when the displayed month changes 
16468              * @param {DatePicker} this
16469              * @param {Date} date The selected month
16470              */
16471         'monthchange': true,
16472         /**
16473              * @event evententer
16474              * Fires when mouse over an event
16475              * @param {Calendar} this
16476              * @param {event} Event
16477              */
16478         'evententer': true,
16479         /**
16480              * @event eventleave
16481              * Fires when the mouse leaves an
16482              * @param {Calendar} this
16483              * @param {event}
16484              */
16485         'eventleave': true,
16486         /**
16487              * @event eventclick
16488              * Fires when the mouse click an
16489              * @param {Calendar} this
16490              * @param {event}
16491              */
16492         'eventclick': true
16493         
16494     });
16495
16496 };
16497
16498 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16499     
16500      /**
16501      * @cfg {Number} startDay
16502      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16503      */
16504     startDay : 0,
16505     
16506     loadMask : false,
16507     
16508     header : false,
16509       
16510     getAutoCreate : function(){
16511         
16512         
16513         var fc_button = function(name, corner, style, content ) {
16514             return Roo.apply({},{
16515                 tag : 'span',
16516                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16517                          (corner.length ?
16518                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16519                             ''
16520                         ),
16521                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16522                 unselectable: 'on'
16523             });
16524         };
16525         
16526         var header = {};
16527         
16528         if(!this.header){
16529             header = {
16530                 tag : 'table',
16531                 cls : 'fc-header',
16532                 style : 'width:100%',
16533                 cn : [
16534                     {
16535                         tag: 'tr',
16536                         cn : [
16537                             {
16538                                 tag : 'td',
16539                                 cls : 'fc-header-left',
16540                                 cn : [
16541                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16542                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16543                                     { tag: 'span', cls: 'fc-header-space' },
16544                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16545
16546
16547                                 ]
16548                             },
16549
16550                             {
16551                                 tag : 'td',
16552                                 cls : 'fc-header-center',
16553                                 cn : [
16554                                     {
16555                                         tag: 'span',
16556                                         cls: 'fc-header-title',
16557                                         cn : {
16558                                             tag: 'H2',
16559                                             html : 'month / year'
16560                                         }
16561                                     }
16562
16563                                 ]
16564                             },
16565                             {
16566                                 tag : 'td',
16567                                 cls : 'fc-header-right',
16568                                 cn : [
16569                               /*      fc_button('month', 'left', '', 'month' ),
16570                                     fc_button('week', '', '', 'week' ),
16571                                     fc_button('day', 'right', '', 'day' )
16572                                 */    
16573
16574                                 ]
16575                             }
16576
16577                         ]
16578                     }
16579                 ]
16580             };
16581         }
16582         
16583         header = this.header;
16584         
16585        
16586         var cal_heads = function() {
16587             var ret = [];
16588             // fixme - handle this.
16589             
16590             for (var i =0; i < Date.dayNames.length; i++) {
16591                 var d = Date.dayNames[i];
16592                 ret.push({
16593                     tag: 'th',
16594                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16595                     html : d.substring(0,3)
16596                 });
16597                 
16598             }
16599             ret[0].cls += ' fc-first';
16600             ret[6].cls += ' fc-last';
16601             return ret;
16602         };
16603         var cal_cell = function(n) {
16604             return  {
16605                 tag: 'td',
16606                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16607                 cn : [
16608                     {
16609                         cn : [
16610                             {
16611                                 cls: 'fc-day-number',
16612                                 html: 'D'
16613                             },
16614                             {
16615                                 cls: 'fc-day-content',
16616                              
16617                                 cn : [
16618                                      {
16619                                         style: 'position: relative;' // height: 17px;
16620                                     }
16621                                 ]
16622                             }
16623                             
16624                             
16625                         ]
16626                     }
16627                 ]
16628                 
16629             }
16630         };
16631         var cal_rows = function() {
16632             
16633             var ret = [];
16634             for (var r = 0; r < 6; r++) {
16635                 var row= {
16636                     tag : 'tr',
16637                     cls : 'fc-week',
16638                     cn : []
16639                 };
16640                 
16641                 for (var i =0; i < Date.dayNames.length; i++) {
16642                     var d = Date.dayNames[i];
16643                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16644
16645                 }
16646                 row.cn[0].cls+=' fc-first';
16647                 row.cn[0].cn[0].style = 'min-height:90px';
16648                 row.cn[6].cls+=' fc-last';
16649                 ret.push(row);
16650                 
16651             }
16652             ret[0].cls += ' fc-first';
16653             ret[4].cls += ' fc-prev-last';
16654             ret[5].cls += ' fc-last';
16655             return ret;
16656             
16657         };
16658         
16659         var cal_table = {
16660             tag: 'table',
16661             cls: 'fc-border-separate',
16662             style : 'width:100%',
16663             cellspacing  : 0,
16664             cn : [
16665                 { 
16666                     tag: 'thead',
16667                     cn : [
16668                         { 
16669                             tag: 'tr',
16670                             cls : 'fc-first fc-last',
16671                             cn : cal_heads()
16672                         }
16673                     ]
16674                 },
16675                 { 
16676                     tag: 'tbody',
16677                     cn : cal_rows()
16678                 }
16679                   
16680             ]
16681         };
16682          
16683          var cfg = {
16684             cls : 'fc fc-ltr',
16685             cn : [
16686                 header,
16687                 {
16688                     cls : 'fc-content',
16689                     style : "position: relative;",
16690                     cn : [
16691                         {
16692                             cls : 'fc-view fc-view-month fc-grid',
16693                             style : 'position: relative',
16694                             unselectable : 'on',
16695                             cn : [
16696                                 {
16697                                     cls : 'fc-event-container',
16698                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16699                                 },
16700                                 cal_table
16701                             ]
16702                         }
16703                     ]
16704     
16705                 }
16706            ] 
16707             
16708         };
16709         
16710          
16711         
16712         return cfg;
16713     },
16714     
16715     
16716     initEvents : function()
16717     {
16718         if(!this.store){
16719             throw "can not find store for calendar";
16720         }
16721         
16722         var mark = {
16723             tag: "div",
16724             cls:"x-dlg-mask",
16725             style: "text-align:center",
16726             cn: [
16727                 {
16728                     tag: "div",
16729                     style: "background-color:white;width:50%;margin:250 auto",
16730                     cn: [
16731                         {
16732                             tag: "img",
16733                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16734                         },
16735                         {
16736                             tag: "span",
16737                             html: "Loading"
16738                         }
16739                         
16740                     ]
16741                 }
16742             ]
16743         };
16744         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16745         
16746         var size = this.el.select('.fc-content', true).first().getSize();
16747         this.maskEl.setSize(size.width, size.height);
16748         this.maskEl.enableDisplayMode("block");
16749         if(!this.loadMask){
16750             this.maskEl.hide();
16751         }
16752         
16753         this.store = Roo.factory(this.store, Roo.data);
16754         this.store.on('load', this.onLoad, this);
16755         this.store.on('beforeload', this.onBeforeLoad, this);
16756         
16757         this.resize();
16758         
16759         this.cells = this.el.select('.fc-day',true);
16760         //Roo.log(this.cells);
16761         this.textNodes = this.el.query('.fc-day-number');
16762         this.cells.addClassOnOver('fc-state-hover');
16763         
16764         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16765         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16766         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16767         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16768         
16769         this.on('monthchange', this.onMonthChange, this);
16770         
16771         this.update(new Date().clearTime());
16772     },
16773     
16774     resize : function() {
16775         var sz  = this.el.getSize();
16776         
16777         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16778         this.el.select('.fc-day-content div',true).setHeight(34);
16779     },
16780     
16781     
16782     // private
16783     showPrevMonth : function(e){
16784         this.update(this.activeDate.add("mo", -1));
16785     },
16786     showToday : function(e){
16787         this.update(new Date().clearTime());
16788     },
16789     // private
16790     showNextMonth : function(e){
16791         this.update(this.activeDate.add("mo", 1));
16792     },
16793
16794     // private
16795     showPrevYear : function(){
16796         this.update(this.activeDate.add("y", -1));
16797     },
16798
16799     // private
16800     showNextYear : function(){
16801         this.update(this.activeDate.add("y", 1));
16802     },
16803
16804     
16805    // private
16806     update : function(date)
16807     {
16808         var vd = this.activeDate;
16809         this.activeDate = date;
16810 //        if(vd && this.el){
16811 //            var t = date.getTime();
16812 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16813 //                Roo.log('using add remove');
16814 //                
16815 //                this.fireEvent('monthchange', this, date);
16816 //                
16817 //                this.cells.removeClass("fc-state-highlight");
16818 //                this.cells.each(function(c){
16819 //                   if(c.dateValue == t){
16820 //                       c.addClass("fc-state-highlight");
16821 //                       setTimeout(function(){
16822 //                            try{c.dom.firstChild.focus();}catch(e){}
16823 //                       }, 50);
16824 //                       return false;
16825 //                   }
16826 //                   return true;
16827 //                });
16828 //                return;
16829 //            }
16830 //        }
16831         
16832         var days = date.getDaysInMonth();
16833         
16834         var firstOfMonth = date.getFirstDateOfMonth();
16835         var startingPos = firstOfMonth.getDay()-this.startDay;
16836         
16837         if(startingPos < this.startDay){
16838             startingPos += 7;
16839         }
16840         
16841         var pm = date.add(Date.MONTH, -1);
16842         var prevStart = pm.getDaysInMonth()-startingPos;
16843 //        
16844         this.cells = this.el.select('.fc-day',true);
16845         this.textNodes = this.el.query('.fc-day-number');
16846         this.cells.addClassOnOver('fc-state-hover');
16847         
16848         var cells = this.cells.elements;
16849         var textEls = this.textNodes;
16850         
16851         Roo.each(cells, function(cell){
16852             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16853         });
16854         
16855         days += startingPos;
16856
16857         // convert everything to numbers so it's fast
16858         var day = 86400000;
16859         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16860         //Roo.log(d);
16861         //Roo.log(pm);
16862         //Roo.log(prevStart);
16863         
16864         var today = new Date().clearTime().getTime();
16865         var sel = date.clearTime().getTime();
16866         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16867         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16868         var ddMatch = this.disabledDatesRE;
16869         var ddText = this.disabledDatesText;
16870         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16871         var ddaysText = this.disabledDaysText;
16872         var format = this.format;
16873         
16874         var setCellClass = function(cal, cell){
16875             cell.row = 0;
16876             cell.events = [];
16877             cell.more = [];
16878             //Roo.log('set Cell Class');
16879             cell.title = "";
16880             var t = d.getTime();
16881             
16882             //Roo.log(d);
16883             
16884             cell.dateValue = t;
16885             if(t == today){
16886                 cell.className += " fc-today";
16887                 cell.className += " fc-state-highlight";
16888                 cell.title = cal.todayText;
16889             }
16890             if(t == sel){
16891                 // disable highlight in other month..
16892                 //cell.className += " fc-state-highlight";
16893                 
16894             }
16895             // disabling
16896             if(t < min) {
16897                 cell.className = " fc-state-disabled";
16898                 cell.title = cal.minText;
16899                 return;
16900             }
16901             if(t > max) {
16902                 cell.className = " fc-state-disabled";
16903                 cell.title = cal.maxText;
16904                 return;
16905             }
16906             if(ddays){
16907                 if(ddays.indexOf(d.getDay()) != -1){
16908                     cell.title = ddaysText;
16909                     cell.className = " fc-state-disabled";
16910                 }
16911             }
16912             if(ddMatch && format){
16913                 var fvalue = d.dateFormat(format);
16914                 if(ddMatch.test(fvalue)){
16915                     cell.title = ddText.replace("%0", fvalue);
16916                     cell.className = " fc-state-disabled";
16917                 }
16918             }
16919             
16920             if (!cell.initialClassName) {
16921                 cell.initialClassName = cell.dom.className;
16922             }
16923             
16924             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16925         };
16926
16927         var i = 0;
16928         
16929         for(; i < startingPos; i++) {
16930             textEls[i].innerHTML = (++prevStart);
16931             d.setDate(d.getDate()+1);
16932             
16933             cells[i].className = "fc-past fc-other-month";
16934             setCellClass(this, cells[i]);
16935         }
16936         
16937         var intDay = 0;
16938         
16939         for(; i < days; i++){
16940             intDay = i - startingPos + 1;
16941             textEls[i].innerHTML = (intDay);
16942             d.setDate(d.getDate()+1);
16943             
16944             cells[i].className = ''; // "x-date-active";
16945             setCellClass(this, cells[i]);
16946         }
16947         var extraDays = 0;
16948         
16949         for(; i < 42; i++) {
16950             textEls[i].innerHTML = (++extraDays);
16951             d.setDate(d.getDate()+1);
16952             
16953             cells[i].className = "fc-future fc-other-month";
16954             setCellClass(this, cells[i]);
16955         }
16956         
16957         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16958         
16959         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16960         
16961         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16962         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16963         
16964         if(totalRows != 6){
16965             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16966             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16967         }
16968         
16969         this.fireEvent('monthchange', this, date);
16970         
16971         
16972         /*
16973         if(!this.internalRender){
16974             var main = this.el.dom.firstChild;
16975             var w = main.offsetWidth;
16976             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16977             Roo.fly(main).setWidth(w);
16978             this.internalRender = true;
16979             // opera does not respect the auto grow header center column
16980             // then, after it gets a width opera refuses to recalculate
16981             // without a second pass
16982             if(Roo.isOpera && !this.secondPass){
16983                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16984                 this.secondPass = true;
16985                 this.update.defer(10, this, [date]);
16986             }
16987         }
16988         */
16989         
16990     },
16991     
16992     findCell : function(dt) {
16993         dt = dt.clearTime().getTime();
16994         var ret = false;
16995         this.cells.each(function(c){
16996             //Roo.log("check " +c.dateValue + '?=' + dt);
16997             if(c.dateValue == dt){
16998                 ret = c;
16999                 return false;
17000             }
17001             return true;
17002         });
17003         
17004         return ret;
17005     },
17006     
17007     findCells : function(ev) {
17008         var s = ev.start.clone().clearTime().getTime();
17009        // Roo.log(s);
17010         var e= ev.end.clone().clearTime().getTime();
17011        // Roo.log(e);
17012         var ret = [];
17013         this.cells.each(function(c){
17014              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17015             
17016             if(c.dateValue > e){
17017                 return ;
17018             }
17019             if(c.dateValue < s){
17020                 return ;
17021             }
17022             ret.push(c);
17023         });
17024         
17025         return ret;    
17026     },
17027     
17028 //    findBestRow: function(cells)
17029 //    {
17030 //        var ret = 0;
17031 //        
17032 //        for (var i =0 ; i < cells.length;i++) {
17033 //            ret  = Math.max(cells[i].rows || 0,ret);
17034 //        }
17035 //        return ret;
17036 //        
17037 //    },
17038     
17039     
17040     addItem : function(ev)
17041     {
17042         // look for vertical location slot in
17043         var cells = this.findCells(ev);
17044         
17045 //        ev.row = this.findBestRow(cells);
17046         
17047         // work out the location.
17048         
17049         var crow = false;
17050         var rows = [];
17051         for(var i =0; i < cells.length; i++) {
17052             
17053             cells[i].row = cells[0].row;
17054             
17055             if(i == 0){
17056                 cells[i].row = cells[i].row + 1;
17057             }
17058             
17059             if (!crow) {
17060                 crow = {
17061                     start : cells[i],
17062                     end :  cells[i]
17063                 };
17064                 continue;
17065             }
17066             if (crow.start.getY() == cells[i].getY()) {
17067                 // on same row.
17068                 crow.end = cells[i];
17069                 continue;
17070             }
17071             // different row.
17072             rows.push(crow);
17073             crow = {
17074                 start: cells[i],
17075                 end : cells[i]
17076             };
17077             
17078         }
17079         
17080         rows.push(crow);
17081         ev.els = [];
17082         ev.rows = rows;
17083         ev.cells = cells;
17084         
17085         cells[0].events.push(ev);
17086         
17087         this.calevents.push(ev);
17088     },
17089     
17090     clearEvents: function() {
17091         
17092         if(!this.calevents){
17093             return;
17094         }
17095         
17096         Roo.each(this.cells.elements, function(c){
17097             c.row = 0;
17098             c.events = [];
17099             c.more = [];
17100         });
17101         
17102         Roo.each(this.calevents, function(e) {
17103             Roo.each(e.els, function(el) {
17104                 el.un('mouseenter' ,this.onEventEnter, this);
17105                 el.un('mouseleave' ,this.onEventLeave, this);
17106                 el.remove();
17107             },this);
17108         },this);
17109         
17110         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17111             e.remove();
17112         });
17113         
17114     },
17115     
17116     renderEvents: function()
17117     {   
17118         var _this = this;
17119         
17120         this.cells.each(function(c) {
17121             
17122             if(c.row < 5){
17123                 return;
17124             }
17125             
17126             var ev = c.events;
17127             
17128             var r = 4;
17129             if(c.row != c.events.length){
17130                 r = 4 - (4 - (c.row - c.events.length));
17131             }
17132             
17133             c.events = ev.slice(0, r);
17134             c.more = ev.slice(r);
17135             
17136             if(c.more.length && c.more.length == 1){
17137                 c.events.push(c.more.pop());
17138             }
17139             
17140             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17141             
17142         });
17143             
17144         this.cells.each(function(c) {
17145             
17146             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17147             
17148             
17149             for (var e = 0; e < c.events.length; e++){
17150                 var ev = c.events[e];
17151                 var rows = ev.rows;
17152                 
17153                 for(var i = 0; i < rows.length; i++) {
17154                 
17155                     // how many rows should it span..
17156
17157                     var  cfg = {
17158                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17159                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17160
17161                         unselectable : "on",
17162                         cn : [
17163                             {
17164                                 cls: 'fc-event-inner',
17165                                 cn : [
17166     //                                {
17167     //                                  tag:'span',
17168     //                                  cls: 'fc-event-time',
17169     //                                  html : cells.length > 1 ? '' : ev.time
17170     //                                },
17171                                     {
17172                                       tag:'span',
17173                                       cls: 'fc-event-title',
17174                                       html : String.format('{0}', ev.title)
17175                                     }
17176
17177
17178                                 ]
17179                             },
17180                             {
17181                                 cls: 'ui-resizable-handle ui-resizable-e',
17182                                 html : '&nbsp;&nbsp;&nbsp'
17183                             }
17184
17185                         ]
17186                     };
17187
17188                     if (i == 0) {
17189                         cfg.cls += ' fc-event-start';
17190                     }
17191                     if ((i+1) == rows.length) {
17192                         cfg.cls += ' fc-event-end';
17193                     }
17194
17195                     var ctr = _this.el.select('.fc-event-container',true).first();
17196                     var cg = ctr.createChild(cfg);
17197
17198                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17199                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17200
17201                     var r = (c.more.length) ? 1 : 0;
17202                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17203                     cg.setWidth(ebox.right - sbox.x -2);
17204
17205                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17206                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17207                     cg.on('click', _this.onEventClick, _this, ev);
17208
17209                     ev.els.push(cg);
17210                     
17211                 }
17212                 
17213             }
17214             
17215             
17216             if(c.more.length){
17217                 var  cfg = {
17218                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17219                     style : 'position: absolute',
17220                     unselectable : "on",
17221                     cn : [
17222                         {
17223                             cls: 'fc-event-inner',
17224                             cn : [
17225                                 {
17226                                   tag:'span',
17227                                   cls: 'fc-event-title',
17228                                   html : 'More'
17229                                 }
17230
17231
17232                             ]
17233                         },
17234                         {
17235                             cls: 'ui-resizable-handle ui-resizable-e',
17236                             html : '&nbsp;&nbsp;&nbsp'
17237                         }
17238
17239                     ]
17240                 };
17241
17242                 var ctr = _this.el.select('.fc-event-container',true).first();
17243                 var cg = ctr.createChild(cfg);
17244
17245                 var sbox = c.select('.fc-day-content',true).first().getBox();
17246                 var ebox = c.select('.fc-day-content',true).first().getBox();
17247                 //Roo.log(cg);
17248                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17249                 cg.setWidth(ebox.right - sbox.x -2);
17250
17251                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17252                 
17253             }
17254             
17255         });
17256         
17257         
17258         
17259     },
17260     
17261     onEventEnter: function (e, el,event,d) {
17262         this.fireEvent('evententer', this, el, event);
17263     },
17264     
17265     onEventLeave: function (e, el,event,d) {
17266         this.fireEvent('eventleave', this, el, event);
17267     },
17268     
17269     onEventClick: function (e, el,event,d) {
17270         this.fireEvent('eventclick', this, el, event);
17271     },
17272     
17273     onMonthChange: function () {
17274         this.store.load();
17275     },
17276     
17277     onMoreEventClick: function(e, el, more)
17278     {
17279         var _this = this;
17280         
17281         this.calpopover.placement = 'right';
17282         this.calpopover.setTitle('More');
17283         
17284         this.calpopover.setContent('');
17285         
17286         var ctr = this.calpopover.el.select('.popover-content', true).first();
17287         
17288         Roo.each(more, function(m){
17289             var cfg = {
17290                 cls : 'fc-event-hori fc-event-draggable',
17291                 html : m.title
17292             };
17293             var cg = ctr.createChild(cfg);
17294             
17295             cg.on('click', _this.onEventClick, _this, m);
17296         });
17297         
17298         this.calpopover.show(el);
17299         
17300         
17301     },
17302     
17303     onLoad: function () 
17304     {   
17305         this.calevents = [];
17306         var cal = this;
17307         
17308         if(this.store.getCount() > 0){
17309             this.store.data.each(function(d){
17310                cal.addItem({
17311                     id : d.data.id,
17312                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17313                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17314                     time : d.data.start_time,
17315                     title : d.data.title,
17316                     description : d.data.description,
17317                     venue : d.data.venue
17318                 });
17319             });
17320         }
17321         
17322         this.renderEvents();
17323         
17324         if(this.calevents.length && this.loadMask){
17325             this.maskEl.hide();
17326         }
17327     },
17328     
17329     onBeforeLoad: function()
17330     {
17331         this.clearEvents();
17332         if(this.loadMask){
17333             this.maskEl.show();
17334         }
17335     }
17336 });
17337
17338  
17339  /*
17340  * - LGPL
17341  *
17342  * element
17343  * 
17344  */
17345
17346 /**
17347  * @class Roo.bootstrap.Popover
17348  * @extends Roo.bootstrap.Component
17349  * Bootstrap Popover class
17350  * @cfg {String} html contents of the popover   (or false to use children..)
17351  * @cfg {String} title of popover (or false to hide)
17352  * @cfg {String} placement how it is placed
17353  * @cfg {String} trigger click || hover (or false to trigger manually)
17354  * @cfg {String} over what (parent or false to trigger manually.)
17355  * @cfg {Number} delay - delay before showing
17356  
17357  * @constructor
17358  * Create a new Popover
17359  * @param {Object} config The config object
17360  */
17361
17362 Roo.bootstrap.Popover = function(config){
17363     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17364     
17365     this.addEvents({
17366         // raw events
17367          /**
17368          * @event show
17369          * After the popover show
17370          * 
17371          * @param {Roo.bootstrap.Popover} this
17372          */
17373         "show" : true,
17374         /**
17375          * @event hide
17376          * After the popover hide
17377          * 
17378          * @param {Roo.bootstrap.Popover} this
17379          */
17380         "hide" : true
17381     });
17382 };
17383
17384 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17385     
17386     title: 'Fill in a title',
17387     html: false,
17388     
17389     placement : 'right',
17390     trigger : 'hover', // hover
17391     
17392     delay : 0,
17393     
17394     over: 'parent',
17395     
17396     can_build_overlaid : false,
17397     
17398     getChildContainer : function()
17399     {
17400         return this.el.select('.popover-content',true).first();
17401     },
17402     
17403     getAutoCreate : function(){
17404          
17405         var cfg = {
17406            cls : 'popover roo-dynamic',
17407            style: 'display:block',
17408            cn : [
17409                 {
17410                     cls : 'arrow'
17411                 },
17412                 {
17413                     cls : 'popover-inner',
17414                     cn : [
17415                         {
17416                             tag: 'h3',
17417                             cls: 'popover-title',
17418                             html : this.title
17419                         },
17420                         {
17421                             cls : 'popover-content',
17422                             html : this.html
17423                         }
17424                     ]
17425                     
17426                 }
17427            ]
17428         };
17429         
17430         return cfg;
17431     },
17432     setTitle: function(str)
17433     {
17434         this.title = str;
17435         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17436     },
17437     setContent: function(str)
17438     {
17439         this.html = str;
17440         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17441     },
17442     // as it get's added to the bottom of the page.
17443     onRender : function(ct, position)
17444     {
17445         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17446         if(!this.el){
17447             var cfg = Roo.apply({},  this.getAutoCreate());
17448             cfg.id = Roo.id();
17449             
17450             if (this.cls) {
17451                 cfg.cls += ' ' + this.cls;
17452             }
17453             if (this.style) {
17454                 cfg.style = this.style;
17455             }
17456             //Roo.log("adding to ");
17457             this.el = Roo.get(document.body).createChild(cfg, position);
17458 //            Roo.log(this.el);
17459         }
17460         this.initEvents();
17461     },
17462     
17463     initEvents : function()
17464     {
17465         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17466         this.el.enableDisplayMode('block');
17467         this.el.hide();
17468         if (this.over === false) {
17469             return; 
17470         }
17471         if (this.triggers === false) {
17472             return;
17473         }
17474         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17475         var triggers = this.trigger ? this.trigger.split(' ') : [];
17476         Roo.each(triggers, function(trigger) {
17477         
17478             if (trigger == 'click') {
17479                 on_el.on('click', this.toggle, this);
17480             } else if (trigger != 'manual') {
17481                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17482                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17483       
17484                 on_el.on(eventIn  ,this.enter, this);
17485                 on_el.on(eventOut, this.leave, this);
17486             }
17487         }, this);
17488         
17489     },
17490     
17491     
17492     // private
17493     timeout : null,
17494     hoverState : null,
17495     
17496     toggle : function () {
17497         this.hoverState == 'in' ? this.leave() : this.enter();
17498     },
17499     
17500     enter : function () {
17501         
17502         clearTimeout(this.timeout);
17503     
17504         this.hoverState = 'in';
17505     
17506         if (!this.delay || !this.delay.show) {
17507             this.show();
17508             return;
17509         }
17510         var _t = this;
17511         this.timeout = setTimeout(function () {
17512             if (_t.hoverState == 'in') {
17513                 _t.show();
17514             }
17515         }, this.delay.show)
17516     },
17517     
17518     leave : function() {
17519         clearTimeout(this.timeout);
17520     
17521         this.hoverState = 'out';
17522     
17523         if (!this.delay || !this.delay.hide) {
17524             this.hide();
17525             return;
17526         }
17527         var _t = this;
17528         this.timeout = setTimeout(function () {
17529             if (_t.hoverState == 'out') {
17530                 _t.hide();
17531             }
17532         }, this.delay.hide)
17533     },
17534     
17535     show : function (on_el)
17536     {
17537         if (!on_el) {
17538             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17539         }
17540         
17541         // set content.
17542         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17543         if (this.html !== false) {
17544             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17545         }
17546         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17547         if (!this.title.length) {
17548             this.el.select('.popover-title',true).hide();
17549         }
17550         
17551         var placement = typeof this.placement == 'function' ?
17552             this.placement.call(this, this.el, on_el) :
17553             this.placement;
17554             
17555         var autoToken = /\s?auto?\s?/i;
17556         var autoPlace = autoToken.test(placement);
17557         if (autoPlace) {
17558             placement = placement.replace(autoToken, '') || 'top';
17559         }
17560         
17561         //this.el.detach()
17562         //this.el.setXY([0,0]);
17563         this.el.show();
17564         this.el.dom.style.display='block';
17565         this.el.addClass(placement);
17566         
17567         //this.el.appendTo(on_el);
17568         
17569         var p = this.getPosition();
17570         var box = this.el.getBox();
17571         
17572         if (autoPlace) {
17573             // fixme..
17574         }
17575         var align = Roo.bootstrap.Popover.alignment[placement];
17576         
17577 //        Roo.log(align);
17578         this.el.alignTo(on_el, align[0],align[1]);
17579         //var arrow = this.el.select('.arrow',true).first();
17580         //arrow.set(align[2], 
17581         
17582         this.el.addClass('in');
17583         
17584         
17585         if (this.el.hasClass('fade')) {
17586             // fade it?
17587         }
17588         
17589         this.hoverState = 'in';
17590         
17591         this.fireEvent('show', this);
17592         
17593     },
17594     hide : function()
17595     {
17596         this.el.setXY([0,0]);
17597         this.el.removeClass('in');
17598         this.el.hide();
17599         this.hoverState = null;
17600         
17601         this.fireEvent('hide', this);
17602     }
17603     
17604 });
17605
17606 Roo.bootstrap.Popover.alignment = {
17607     'left' : ['r-l', [-10,0], 'right'],
17608     'right' : ['l-r', [10,0], 'left'],
17609     'bottom' : ['t-b', [0,10], 'top'],
17610     'top' : [ 'b-t', [0,-10], 'bottom']
17611 };
17612
17613  /*
17614  * - LGPL
17615  *
17616  * Progress
17617  * 
17618  */
17619
17620 /**
17621  * @class Roo.bootstrap.Progress
17622  * @extends Roo.bootstrap.Component
17623  * Bootstrap Progress class
17624  * @cfg {Boolean} striped striped of the progress bar
17625  * @cfg {Boolean} active animated of the progress bar
17626  * 
17627  * 
17628  * @constructor
17629  * Create a new Progress
17630  * @param {Object} config The config object
17631  */
17632
17633 Roo.bootstrap.Progress = function(config){
17634     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17635 };
17636
17637 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17638     
17639     striped : false,
17640     active: false,
17641     
17642     getAutoCreate : function(){
17643         var cfg = {
17644             tag: 'div',
17645             cls: 'progress'
17646         };
17647         
17648         
17649         if(this.striped){
17650             cfg.cls += ' progress-striped';
17651         }
17652       
17653         if(this.active){
17654             cfg.cls += ' active';
17655         }
17656         
17657         
17658         return cfg;
17659     }
17660    
17661 });
17662
17663  
17664
17665  /*
17666  * - LGPL
17667  *
17668  * ProgressBar
17669  * 
17670  */
17671
17672 /**
17673  * @class Roo.bootstrap.ProgressBar
17674  * @extends Roo.bootstrap.Component
17675  * Bootstrap ProgressBar class
17676  * @cfg {Number} aria_valuenow aria-value now
17677  * @cfg {Number} aria_valuemin aria-value min
17678  * @cfg {Number} aria_valuemax aria-value max
17679  * @cfg {String} label label for the progress bar
17680  * @cfg {String} panel (success | info | warning | danger )
17681  * @cfg {String} role role of the progress bar
17682  * @cfg {String} sr_only text
17683  * 
17684  * 
17685  * @constructor
17686  * Create a new ProgressBar
17687  * @param {Object} config The config object
17688  */
17689
17690 Roo.bootstrap.ProgressBar = function(config){
17691     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17692 };
17693
17694 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17695     
17696     aria_valuenow : 0,
17697     aria_valuemin : 0,
17698     aria_valuemax : 100,
17699     label : false,
17700     panel : false,
17701     role : false,
17702     sr_only: false,
17703     
17704     getAutoCreate : function()
17705     {
17706         
17707         var cfg = {
17708             tag: 'div',
17709             cls: 'progress-bar',
17710             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17711         };
17712         
17713         if(this.sr_only){
17714             cfg.cn = {
17715                 tag: 'span',
17716                 cls: 'sr-only',
17717                 html: this.sr_only
17718             }
17719         }
17720         
17721         if(this.role){
17722             cfg.role = this.role;
17723         }
17724         
17725         if(this.aria_valuenow){
17726             cfg['aria-valuenow'] = this.aria_valuenow;
17727         }
17728         
17729         if(this.aria_valuemin){
17730             cfg['aria-valuemin'] = this.aria_valuemin;
17731         }
17732         
17733         if(this.aria_valuemax){
17734             cfg['aria-valuemax'] = this.aria_valuemax;
17735         }
17736         
17737         if(this.label && !this.sr_only){
17738             cfg.html = this.label;
17739         }
17740         
17741         if(this.panel){
17742             cfg.cls += ' progress-bar-' + this.panel;
17743         }
17744         
17745         return cfg;
17746     },
17747     
17748     update : function(aria_valuenow)
17749     {
17750         this.aria_valuenow = aria_valuenow;
17751         
17752         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17753     }
17754    
17755 });
17756
17757  
17758
17759  /*
17760  * - LGPL
17761  *
17762  * column
17763  * 
17764  */
17765
17766 /**
17767  * @class Roo.bootstrap.TabGroup
17768  * @extends Roo.bootstrap.Column
17769  * Bootstrap Column class
17770  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17771  * @cfg {Boolean} carousel true to make the group behave like a carousel
17772  * @cfg {Boolean} bullets show bullets for the panels
17773  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17774  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17775  * @cfg {Boolean} showarrow (true|false) show arrow default true
17776  * 
17777  * @constructor
17778  * Create a new TabGroup
17779  * @param {Object} config The config object
17780  */
17781
17782 Roo.bootstrap.TabGroup = function(config){
17783     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17784     if (!this.navId) {
17785         this.navId = Roo.id();
17786     }
17787     this.tabs = [];
17788     Roo.bootstrap.TabGroup.register(this);
17789     
17790 };
17791
17792 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17793     
17794     carousel : false,
17795     transition : false,
17796     bullets : 0,
17797     timer : 0,
17798     autoslide : false,
17799     slideFn : false,
17800     slideOnTouch : false,
17801     showarrow : true,
17802     
17803     getAutoCreate : function()
17804     {
17805         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17806         
17807         cfg.cls += ' tab-content';
17808         
17809         if (this.carousel) {
17810             cfg.cls += ' carousel slide';
17811             
17812             cfg.cn = [{
17813                cls : 'carousel-inner',
17814                cn : []
17815             }];
17816         
17817             if(this.bullets  && !Roo.isTouch){
17818                 
17819                 var bullets = {
17820                     cls : 'carousel-bullets',
17821                     cn : []
17822                 };
17823                
17824                 if(this.bullets_cls){
17825                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17826                 }
17827                 
17828                 bullets.cn.push({
17829                     cls : 'clear'
17830                 });
17831                 
17832                 cfg.cn[0].cn.push(bullets);
17833             }
17834             
17835             if(this.showarrow){
17836                 cfg.cn[0].cn.push({
17837                     tag : 'div',
17838                     class : 'carousel-arrow',
17839                     cn : [
17840                         {
17841                             tag : 'div',
17842                             class : 'carousel-prev',
17843                             cn : [
17844                                 {
17845                                     tag : 'i',
17846                                     class : 'fa fa-chevron-left'
17847                                 }
17848                             ]
17849                         },
17850                         {
17851                             tag : 'div',
17852                             class : 'carousel-next',
17853                             cn : [
17854                                 {
17855                                     tag : 'i',
17856                                     class : 'fa fa-chevron-right'
17857                                 }
17858                             ]
17859                         }
17860                     ]
17861                 });
17862             }
17863             
17864         }
17865         
17866         return cfg;
17867     },
17868     
17869     initEvents:  function()
17870     {
17871 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17872 //            this.el.on("touchstart", this.onTouchStart, this);
17873 //        }
17874         
17875         if(this.autoslide){
17876             var _this = this;
17877             
17878             this.slideFn = window.setInterval(function() {
17879                 _this.showPanelNext();
17880             }, this.timer);
17881         }
17882         
17883         if(this.showarrow){
17884             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17885             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17886         }
17887         
17888         
17889     },
17890     
17891 //    onTouchStart : function(e, el, o)
17892 //    {
17893 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17894 //            return;
17895 //        }
17896 //        
17897 //        this.showPanelNext();
17898 //    },
17899     
17900     
17901     getChildContainer : function()
17902     {
17903         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17904     },
17905     
17906     /**
17907     * register a Navigation item
17908     * @param {Roo.bootstrap.NavItem} the navitem to add
17909     */
17910     register : function(item)
17911     {
17912         this.tabs.push( item);
17913         item.navId = this.navId; // not really needed..
17914         this.addBullet();
17915     
17916     },
17917     
17918     getActivePanel : function()
17919     {
17920         var r = false;
17921         Roo.each(this.tabs, function(t) {
17922             if (t.active) {
17923                 r = t;
17924                 return false;
17925             }
17926             return null;
17927         });
17928         return r;
17929         
17930     },
17931     getPanelByName : function(n)
17932     {
17933         var r = false;
17934         Roo.each(this.tabs, function(t) {
17935             if (t.tabId == n) {
17936                 r = t;
17937                 return false;
17938             }
17939             return null;
17940         });
17941         return r;
17942     },
17943     indexOfPanel : function(p)
17944     {
17945         var r = false;
17946         Roo.each(this.tabs, function(t,i) {
17947             if (t.tabId == p.tabId) {
17948                 r = i;
17949                 return false;
17950             }
17951             return null;
17952         });
17953         return r;
17954     },
17955     /**
17956      * show a specific panel
17957      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17958      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17959      */
17960     showPanel : function (pan)
17961     {
17962         if(this.transition || typeof(pan) == 'undefined'){
17963             Roo.log("waiting for the transitionend");
17964             return;
17965         }
17966         
17967         if (typeof(pan) == 'number') {
17968             pan = this.tabs[pan];
17969         }
17970         
17971         if (typeof(pan) == 'string') {
17972             pan = this.getPanelByName(pan);
17973         }
17974         
17975         var cur = this.getActivePanel();
17976         
17977         if(!pan || !cur){
17978             Roo.log('pan or acitve pan is undefined');
17979             return false;
17980         }
17981         
17982         if (pan.tabId == this.getActivePanel().tabId) {
17983             return true;
17984         }
17985         
17986         if (false === cur.fireEvent('beforedeactivate')) {
17987             return false;
17988         }
17989         
17990         if(this.bullets > 0 && !Roo.isTouch){
17991             this.setActiveBullet(this.indexOfPanel(pan));
17992         }
17993         
17994         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17995             
17996             this.transition = true;
17997             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
17998             var lr = dir == 'next' ? 'left' : 'right';
17999             pan.el.addClass(dir); // or prev
18000             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18001             cur.el.addClass(lr); // or right
18002             pan.el.addClass(lr);
18003             
18004             var _this = this;
18005             cur.el.on('transitionend', function() {
18006                 Roo.log("trans end?");
18007                 
18008                 pan.el.removeClass([lr,dir]);
18009                 pan.setActive(true);
18010                 
18011                 cur.el.removeClass([lr]);
18012                 cur.setActive(false);
18013                 
18014                 _this.transition = false;
18015                 
18016             }, this, { single:  true } );
18017             
18018             return true;
18019         }
18020         
18021         cur.setActive(false);
18022         pan.setActive(true);
18023         
18024         return true;
18025         
18026     },
18027     showPanelNext : function()
18028     {
18029         var i = this.indexOfPanel(this.getActivePanel());
18030         
18031         if (i >= this.tabs.length - 1 && !this.autoslide) {
18032             return;
18033         }
18034         
18035         if (i >= this.tabs.length - 1 && this.autoslide) {
18036             i = -1;
18037         }
18038         
18039         this.showPanel(this.tabs[i+1]);
18040     },
18041     
18042     showPanelPrev : function()
18043     {
18044         var i = this.indexOfPanel(this.getActivePanel());
18045         
18046         if (i  < 1 && !this.autoslide) {
18047             return;
18048         }
18049         
18050         if (i < 1 && this.autoslide) {
18051             i = this.tabs.length;
18052         }
18053         
18054         this.showPanel(this.tabs[i-1]);
18055     },
18056     
18057     
18058     addBullet: function()
18059     {
18060         if(!this.bullets || Roo.isTouch){
18061             return;
18062         }
18063         var ctr = this.el.select('.carousel-bullets',true).first();
18064         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18065         var bullet = ctr.createChild({
18066             cls : 'bullet bullet-' + i
18067         },ctr.dom.lastChild);
18068         
18069         
18070         var _this = this;
18071         
18072         bullet.on('click', (function(e, el, o, ii, t){
18073
18074             e.preventDefault();
18075
18076             this.showPanel(ii);
18077
18078             if(this.autoslide && this.slideFn){
18079                 clearInterval(this.slideFn);
18080                 this.slideFn = window.setInterval(function() {
18081                     _this.showPanelNext();
18082                 }, this.timer);
18083             }
18084
18085         }).createDelegate(this, [i, bullet], true));
18086                 
18087         
18088     },
18089      
18090     setActiveBullet : function(i)
18091     {
18092         if(Roo.isTouch){
18093             return;
18094         }
18095         
18096         Roo.each(this.el.select('.bullet', true).elements, function(el){
18097             el.removeClass('selected');
18098         });
18099
18100         var bullet = this.el.select('.bullet-' + i, true).first();
18101         
18102         if(!bullet){
18103             return;
18104         }
18105         
18106         bullet.addClass('selected');
18107     }
18108     
18109     
18110   
18111 });
18112
18113  
18114
18115  
18116  
18117 Roo.apply(Roo.bootstrap.TabGroup, {
18118     
18119     groups: {},
18120      /**
18121     * register a Navigation Group
18122     * @param {Roo.bootstrap.NavGroup} the navgroup to add
18123     */
18124     register : function(navgrp)
18125     {
18126         this.groups[navgrp.navId] = navgrp;
18127         
18128     },
18129     /**
18130     * fetch a Navigation Group based on the navigation ID
18131     * if one does not exist , it will get created.
18132     * @param {string} the navgroup to add
18133     * @returns {Roo.bootstrap.NavGroup} the navgroup 
18134     */
18135     get: function(navId) {
18136         if (typeof(this.groups[navId]) == 'undefined') {
18137             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18138         }
18139         return this.groups[navId] ;
18140     }
18141     
18142     
18143     
18144 });
18145
18146  /*
18147  * - LGPL
18148  *
18149  * TabPanel
18150  * 
18151  */
18152
18153 /**
18154  * @class Roo.bootstrap.TabPanel
18155  * @extends Roo.bootstrap.Component
18156  * Bootstrap TabPanel class
18157  * @cfg {Boolean} active panel active
18158  * @cfg {String} html panel content
18159  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18160  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18161  * @cfg {String} href click to link..
18162  * 
18163  * 
18164  * @constructor
18165  * Create a new TabPanel
18166  * @param {Object} config The config object
18167  */
18168
18169 Roo.bootstrap.TabPanel = function(config){
18170     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18171     this.addEvents({
18172         /**
18173              * @event changed
18174              * Fires when the active status changes
18175              * @param {Roo.bootstrap.TabPanel} this
18176              * @param {Boolean} state the new state
18177             
18178          */
18179         'changed': true,
18180         /**
18181              * @event beforedeactivate
18182              * Fires before a tab is de-activated - can be used to do validation on a form.
18183              * @param {Roo.bootstrap.TabPanel} this
18184              * @return {Boolean} false if there is an error
18185             
18186          */
18187         'beforedeactivate': true
18188      });
18189     
18190     this.tabId = this.tabId || Roo.id();
18191   
18192 };
18193
18194 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
18195     
18196     active: false,
18197     html: false,
18198     tabId: false,
18199     navId : false,
18200     href : '',
18201     
18202     getAutoCreate : function(){
18203         var cfg = {
18204             tag: 'div',
18205             // item is needed for carousel - not sure if it has any effect otherwise
18206             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18207             html: this.html || ''
18208         };
18209         
18210         if(this.active){
18211             cfg.cls += ' active';
18212         }
18213         
18214         if(this.tabId){
18215             cfg.tabId = this.tabId;
18216         }
18217         
18218         
18219         return cfg;
18220     },
18221     
18222     initEvents:  function()
18223     {
18224         var p = this.parent();
18225         
18226         this.navId = this.navId || p.navId;
18227         
18228         if (typeof(this.navId) != 'undefined') {
18229             // not really needed.. but just in case.. parent should be a NavGroup.
18230             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18231             
18232             tg.register(this);
18233             
18234             var i = tg.tabs.length - 1;
18235             
18236             if(this.active && tg.bullets > 0 && i < tg.bullets){
18237                 tg.setActiveBullet(i);
18238             }
18239         }
18240         
18241         this.el.on('click', this.onClick, this);
18242         
18243         if(Roo.isTouch){
18244             this.el.on("touchstart", this.onTouchStart, this);
18245             this.el.on("touchmove", this.onTouchMove, this);
18246             this.el.on("touchend", this.onTouchEnd, this);
18247         }
18248         
18249     },
18250     
18251     onRender : function(ct, position)
18252     {
18253         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18254     },
18255     
18256     setActive : function(state)
18257     {
18258         Roo.log("panel - set active " + this.tabId + "=" + state);
18259         
18260         this.active = state;
18261         if (!state) {
18262             this.el.removeClass('active');
18263             
18264         } else  if (!this.el.hasClass('active')) {
18265             this.el.addClass('active');
18266         }
18267         
18268         this.fireEvent('changed', this, state);
18269     },
18270     
18271     onClick : function(e)
18272     {
18273         e.preventDefault();
18274         
18275         if(!this.href.length){
18276             return;
18277         }
18278         
18279         window.location.href = this.href;
18280     },
18281     
18282     startX : 0,
18283     startY : 0,
18284     endX : 0,
18285     endY : 0,
18286     swiping : false,
18287     
18288     onTouchStart : function(e)
18289     {
18290         this.swiping = false;
18291         
18292         this.startX = e.browserEvent.touches[0].clientX;
18293         this.startY = e.browserEvent.touches[0].clientY;
18294     },
18295     
18296     onTouchMove : function(e)
18297     {
18298         this.swiping = true;
18299         
18300         this.endX = e.browserEvent.touches[0].clientX;
18301         this.endY = e.browserEvent.touches[0].clientY;
18302     },
18303     
18304     onTouchEnd : function(e)
18305     {
18306         if(!this.swiping){
18307             this.onClick(e);
18308             return;
18309         }
18310         
18311         var tabGroup = this.parent();
18312         
18313         if(this.endX > this.startX){ // swiping right
18314             tabGroup.showPanelPrev();
18315             return;
18316         }
18317         
18318         if(this.startX > this.endX){ // swiping left
18319             tabGroup.showPanelNext();
18320             return;
18321         }
18322     }
18323     
18324     
18325 });
18326  
18327
18328  
18329
18330  /*
18331  * - LGPL
18332  *
18333  * DateField
18334  * 
18335  */
18336
18337 /**
18338  * @class Roo.bootstrap.DateField
18339  * @extends Roo.bootstrap.Input
18340  * Bootstrap DateField class
18341  * @cfg {Number} weekStart default 0
18342  * @cfg {String} viewMode default empty, (months|years)
18343  * @cfg {String} minViewMode default empty, (months|years)
18344  * @cfg {Number} startDate default -Infinity
18345  * @cfg {Number} endDate default Infinity
18346  * @cfg {Boolean} todayHighlight default false
18347  * @cfg {Boolean} todayBtn default false
18348  * @cfg {Boolean} calendarWeeks default false
18349  * @cfg {Object} daysOfWeekDisabled default empty
18350  * @cfg {Boolean} singleMode default false (true | false)
18351  * 
18352  * @cfg {Boolean} keyboardNavigation default true
18353  * @cfg {String} language default en
18354  * 
18355  * @constructor
18356  * Create a new DateField
18357  * @param {Object} config The config object
18358  */
18359
18360 Roo.bootstrap.DateField = function(config){
18361     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18362      this.addEvents({
18363             /**
18364              * @event show
18365              * Fires when this field show.
18366              * @param {Roo.bootstrap.DateField} this
18367              * @param {Mixed} date The date value
18368              */
18369             show : true,
18370             /**
18371              * @event show
18372              * Fires when this field hide.
18373              * @param {Roo.bootstrap.DateField} this
18374              * @param {Mixed} date The date value
18375              */
18376             hide : true,
18377             /**
18378              * @event select
18379              * Fires when select a date.
18380              * @param {Roo.bootstrap.DateField} this
18381              * @param {Mixed} date The date value
18382              */
18383             select : true,
18384             /**
18385              * @event beforeselect
18386              * Fires when before select a date.
18387              * @param {Roo.bootstrap.DateField} this
18388              * @param {Mixed} date The date value
18389              */
18390             beforeselect : true
18391         });
18392 };
18393
18394 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18395     
18396     /**
18397      * @cfg {String} format
18398      * The default date format string which can be overriden for localization support.  The format must be
18399      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18400      */
18401     format : "m/d/y",
18402     /**
18403      * @cfg {String} altFormats
18404      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18405      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18406      */
18407     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18408     
18409     weekStart : 0,
18410     
18411     viewMode : '',
18412     
18413     minViewMode : '',
18414     
18415     todayHighlight : false,
18416     
18417     todayBtn: false,
18418     
18419     language: 'en',
18420     
18421     keyboardNavigation: true,
18422     
18423     calendarWeeks: false,
18424     
18425     startDate: -Infinity,
18426     
18427     endDate: Infinity,
18428     
18429     daysOfWeekDisabled: [],
18430     
18431     _events: [],
18432     
18433     singleMode : false,
18434     
18435     UTCDate: function()
18436     {
18437         return new Date(Date.UTC.apply(Date, arguments));
18438     },
18439     
18440     UTCToday: function()
18441     {
18442         var today = new Date();
18443         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18444     },
18445     
18446     getDate: function() {
18447             var d = this.getUTCDate();
18448             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18449     },
18450     
18451     getUTCDate: function() {
18452             return this.date;
18453     },
18454     
18455     setDate: function(d) {
18456             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18457     },
18458     
18459     setUTCDate: function(d) {
18460             this.date = d;
18461             this.setValue(this.formatDate(this.date));
18462     },
18463         
18464     onRender: function(ct, position)
18465     {
18466         
18467         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18468         
18469         this.language = this.language || 'en';
18470         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18471         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18472         
18473         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18474         this.format = this.format || 'm/d/y';
18475         this.isInline = false;
18476         this.isInput = true;
18477         this.component = this.el.select('.add-on', true).first() || false;
18478         this.component = (this.component && this.component.length === 0) ? false : this.component;
18479         this.hasInput = this.component && this.inputEl().length;
18480         
18481         if (typeof(this.minViewMode === 'string')) {
18482             switch (this.minViewMode) {
18483                 case 'months':
18484                     this.minViewMode = 1;
18485                     break;
18486                 case 'years':
18487                     this.minViewMode = 2;
18488                     break;
18489                 default:
18490                     this.minViewMode = 0;
18491                     break;
18492             }
18493         }
18494         
18495         if (typeof(this.viewMode === 'string')) {
18496             switch (this.viewMode) {
18497                 case 'months':
18498                     this.viewMode = 1;
18499                     break;
18500                 case 'years':
18501                     this.viewMode = 2;
18502                     break;
18503                 default:
18504                     this.viewMode = 0;
18505                     break;
18506             }
18507         }
18508                 
18509         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18510         
18511 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18512         
18513         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18514         
18515         this.picker().on('mousedown', this.onMousedown, this);
18516         this.picker().on('click', this.onClick, this);
18517         
18518         this.picker().addClass('datepicker-dropdown');
18519         
18520         this.startViewMode = this.viewMode;
18521         
18522         if(this.singleMode){
18523             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18524                 v.setVisibilityMode(Roo.Element.DISPLAY);
18525                 v.hide();
18526             });
18527             
18528             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18529                 v.setStyle('width', '189px');
18530             });
18531         }
18532         
18533         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18534             if(!this.calendarWeeks){
18535                 v.remove();
18536                 return;
18537             }
18538             
18539             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18540             v.attr('colspan', function(i, val){
18541                 return parseInt(val) + 1;
18542             });
18543         });
18544                         
18545         
18546         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18547         
18548         this.setStartDate(this.startDate);
18549         this.setEndDate(this.endDate);
18550         
18551         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18552         
18553         this.fillDow();
18554         this.fillMonths();
18555         this.update();
18556         this.showMode();
18557         
18558         if(this.isInline) {
18559             this.show();
18560         }
18561     },
18562     
18563     picker : function()
18564     {
18565         return this.pickerEl;
18566 //        return this.el.select('.datepicker', true).first();
18567     },
18568     
18569     fillDow: function()
18570     {
18571         var dowCnt = this.weekStart;
18572         
18573         var dow = {
18574             tag: 'tr',
18575             cn: [
18576                 
18577             ]
18578         };
18579         
18580         if(this.calendarWeeks){
18581             dow.cn.push({
18582                 tag: 'th',
18583                 cls: 'cw',
18584                 html: '&nbsp;'
18585             })
18586         }
18587         
18588         while (dowCnt < this.weekStart + 7) {
18589             dow.cn.push({
18590                 tag: 'th',
18591                 cls: 'dow',
18592                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18593             });
18594         }
18595         
18596         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18597     },
18598     
18599     fillMonths: function()
18600     {    
18601         var i = 0;
18602         var months = this.picker().select('>.datepicker-months td', true).first();
18603         
18604         months.dom.innerHTML = '';
18605         
18606         while (i < 12) {
18607             var month = {
18608                 tag: 'span',
18609                 cls: 'month',
18610                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18611             };
18612             
18613             months.createChild(month);
18614         }
18615         
18616     },
18617     
18618     update: function()
18619     {
18620         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;
18621         
18622         if (this.date < this.startDate) {
18623             this.viewDate = new Date(this.startDate);
18624         } else if (this.date > this.endDate) {
18625             this.viewDate = new Date(this.endDate);
18626         } else {
18627             this.viewDate = new Date(this.date);
18628         }
18629         
18630         this.fill();
18631     },
18632     
18633     fill: function() 
18634     {
18635         var d = new Date(this.viewDate),
18636                 year = d.getUTCFullYear(),
18637                 month = d.getUTCMonth(),
18638                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18639                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18640                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18641                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18642                 currentDate = this.date && this.date.valueOf(),
18643                 today = this.UTCToday();
18644         
18645         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18646         
18647 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18648         
18649 //        this.picker.select('>tfoot th.today').
18650 //                                              .text(dates[this.language].today)
18651 //                                              .toggle(this.todayBtn !== false);
18652     
18653         this.updateNavArrows();
18654         this.fillMonths();
18655                                                 
18656         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18657         
18658         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18659          
18660         prevMonth.setUTCDate(day);
18661         
18662         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18663         
18664         var nextMonth = new Date(prevMonth);
18665         
18666         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18667         
18668         nextMonth = nextMonth.valueOf();
18669         
18670         var fillMonths = false;
18671         
18672         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18673         
18674         while(prevMonth.valueOf() <= nextMonth) {
18675             var clsName = '';
18676             
18677             if (prevMonth.getUTCDay() === this.weekStart) {
18678                 if(fillMonths){
18679                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18680                 }
18681                     
18682                 fillMonths = {
18683                     tag: 'tr',
18684                     cn: []
18685                 };
18686                 
18687                 if(this.calendarWeeks){
18688                     // ISO 8601: First week contains first thursday.
18689                     // ISO also states week starts on Monday, but we can be more abstract here.
18690                     var
18691                     // Start of current week: based on weekstart/current date
18692                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18693                     // Thursday of this week
18694                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18695                     // First Thursday of year, year from thursday
18696                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18697                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18698                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18699                     
18700                     fillMonths.cn.push({
18701                         tag: 'td',
18702                         cls: 'cw',
18703                         html: calWeek
18704                     });
18705                 }
18706             }
18707             
18708             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18709                 clsName += ' old';
18710             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18711                 clsName += ' new';
18712             }
18713             if (this.todayHighlight &&
18714                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18715                 prevMonth.getUTCMonth() == today.getMonth() &&
18716                 prevMonth.getUTCDate() == today.getDate()) {
18717                 clsName += ' today';
18718             }
18719             
18720             if (currentDate && prevMonth.valueOf() === currentDate) {
18721                 clsName += ' active';
18722             }
18723             
18724             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18725                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18726                     clsName += ' disabled';
18727             }
18728             
18729             fillMonths.cn.push({
18730                 tag: 'td',
18731                 cls: 'day ' + clsName,
18732                 html: prevMonth.getDate()
18733             });
18734             
18735             prevMonth.setDate(prevMonth.getDate()+1);
18736         }
18737           
18738         var currentYear = this.date && this.date.getUTCFullYear();
18739         var currentMonth = this.date && this.date.getUTCMonth();
18740         
18741         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18742         
18743         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18744             v.removeClass('active');
18745             
18746             if(currentYear === year && k === currentMonth){
18747                 v.addClass('active');
18748             }
18749             
18750             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18751                 v.addClass('disabled');
18752             }
18753             
18754         });
18755         
18756         
18757         year = parseInt(year/10, 10) * 10;
18758         
18759         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18760         
18761         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18762         
18763         year -= 1;
18764         for (var i = -1; i < 11; i++) {
18765             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18766                 tag: 'span',
18767                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18768                 html: year
18769             });
18770             
18771             year += 1;
18772         }
18773     },
18774     
18775     showMode: function(dir) 
18776     {
18777         if (dir) {
18778             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18779         }
18780         
18781         Roo.each(this.picker().select('>div',true).elements, function(v){
18782             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18783             v.hide();
18784         });
18785         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18786     },
18787     
18788     place: function()
18789     {
18790         if(this.isInline) {
18791             return;
18792         }
18793         
18794         this.picker().removeClass(['bottom', 'top']);
18795         
18796         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18797             /*
18798              * place to the top of element!
18799              *
18800              */
18801             
18802             this.picker().addClass('top');
18803             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18804             
18805             return;
18806         }
18807         
18808         this.picker().addClass('bottom');
18809         
18810         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18811     },
18812     
18813     parseDate : function(value)
18814     {
18815         if(!value || value instanceof Date){
18816             return value;
18817         }
18818         var v = Date.parseDate(value, this.format);
18819         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18820             v = Date.parseDate(value, 'Y-m-d');
18821         }
18822         if(!v && this.altFormats){
18823             if(!this.altFormatsArray){
18824                 this.altFormatsArray = this.altFormats.split("|");
18825             }
18826             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18827                 v = Date.parseDate(value, this.altFormatsArray[i]);
18828             }
18829         }
18830         return v;
18831     },
18832     
18833     formatDate : function(date, fmt)
18834     {   
18835         return (!date || !(date instanceof Date)) ?
18836         date : date.dateFormat(fmt || this.format);
18837     },
18838     
18839     onFocus : function()
18840     {
18841         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18842         this.show();
18843     },
18844     
18845     onBlur : function()
18846     {
18847         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18848         
18849         var d = this.inputEl().getValue();
18850         
18851         this.setValue(d);
18852                 
18853         this.hide();
18854     },
18855     
18856     show : function()
18857     {
18858         this.picker().show();
18859         this.update();
18860         this.place();
18861         
18862         this.fireEvent('show', this, this.date);
18863     },
18864     
18865     hide : function()
18866     {
18867         if(this.isInline) {
18868             return;
18869         }
18870         this.picker().hide();
18871         this.viewMode = this.startViewMode;
18872         this.showMode();
18873         
18874         this.fireEvent('hide', this, this.date);
18875         
18876     },
18877     
18878     onMousedown: function(e)
18879     {
18880         e.stopPropagation();
18881         e.preventDefault();
18882     },
18883     
18884     keyup: function(e)
18885     {
18886         Roo.bootstrap.DateField.superclass.keyup.call(this);
18887         this.update();
18888     },
18889
18890     setValue: function(v)
18891     {
18892         if(this.fireEvent('beforeselect', this, v) !== false){
18893             var d = new Date(this.parseDate(v) ).clearTime();
18894         
18895             if(isNaN(d.getTime())){
18896                 this.date = this.viewDate = '';
18897                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18898                 return;
18899             }
18900
18901             v = this.formatDate(d);
18902
18903             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18904
18905             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18906
18907             this.update();
18908
18909             this.fireEvent('select', this, this.date);
18910         }
18911     },
18912     
18913     getValue: function()
18914     {
18915         return this.formatDate(this.date);
18916     },
18917     
18918     fireKey: function(e)
18919     {
18920         if (!this.picker().isVisible()){
18921             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18922                 this.show();
18923             }
18924             return;
18925         }
18926         
18927         var dateChanged = false,
18928         dir, day, month,
18929         newDate, newViewDate;
18930         
18931         switch(e.keyCode){
18932             case 27: // escape
18933                 this.hide();
18934                 e.preventDefault();
18935                 break;
18936             case 37: // left
18937             case 39: // right
18938                 if (!this.keyboardNavigation) {
18939                     break;
18940                 }
18941                 dir = e.keyCode == 37 ? -1 : 1;
18942                 
18943                 if (e.ctrlKey){
18944                     newDate = this.moveYear(this.date, dir);
18945                     newViewDate = this.moveYear(this.viewDate, dir);
18946                 } else if (e.shiftKey){
18947                     newDate = this.moveMonth(this.date, dir);
18948                     newViewDate = this.moveMonth(this.viewDate, dir);
18949                 } else {
18950                     newDate = new Date(this.date);
18951                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18952                     newViewDate = new Date(this.viewDate);
18953                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18954                 }
18955                 if (this.dateWithinRange(newDate)){
18956                     this.date = newDate;
18957                     this.viewDate = newViewDate;
18958                     this.setValue(this.formatDate(this.date));
18959 //                    this.update();
18960                     e.preventDefault();
18961                     dateChanged = true;
18962                 }
18963                 break;
18964             case 38: // up
18965             case 40: // down
18966                 if (!this.keyboardNavigation) {
18967                     break;
18968                 }
18969                 dir = e.keyCode == 38 ? -1 : 1;
18970                 if (e.ctrlKey){
18971                     newDate = this.moveYear(this.date, dir);
18972                     newViewDate = this.moveYear(this.viewDate, dir);
18973                 } else if (e.shiftKey){
18974                     newDate = this.moveMonth(this.date, dir);
18975                     newViewDate = this.moveMonth(this.viewDate, dir);
18976                 } else {
18977                     newDate = new Date(this.date);
18978                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18979                     newViewDate = new Date(this.viewDate);
18980                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18981                 }
18982                 if (this.dateWithinRange(newDate)){
18983                     this.date = newDate;
18984                     this.viewDate = newViewDate;
18985                     this.setValue(this.formatDate(this.date));
18986 //                    this.update();
18987                     e.preventDefault();
18988                     dateChanged = true;
18989                 }
18990                 break;
18991             case 13: // enter
18992                 this.setValue(this.formatDate(this.date));
18993                 this.hide();
18994                 e.preventDefault();
18995                 break;
18996             case 9: // tab
18997                 this.setValue(this.formatDate(this.date));
18998                 this.hide();
18999                 break;
19000             case 16: // shift
19001             case 17: // ctrl
19002             case 18: // alt
19003                 break;
19004             default :
19005                 this.hide();
19006                 
19007         }
19008     },
19009     
19010     
19011     onClick: function(e) 
19012     {
19013         e.stopPropagation();
19014         e.preventDefault();
19015         
19016         var target = e.getTarget();
19017         
19018         if(target.nodeName.toLowerCase() === 'i'){
19019             target = Roo.get(target).dom.parentNode;
19020         }
19021         
19022         var nodeName = target.nodeName;
19023         var className = target.className;
19024         var html = target.innerHTML;
19025         //Roo.log(nodeName);
19026         
19027         switch(nodeName.toLowerCase()) {
19028             case 'th':
19029                 switch(className) {
19030                     case 'switch':
19031                         this.showMode(1);
19032                         break;
19033                     case 'prev':
19034                     case 'next':
19035                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19036                         switch(this.viewMode){
19037                                 case 0:
19038                                         this.viewDate = this.moveMonth(this.viewDate, dir);
19039                                         break;
19040                                 case 1:
19041                                 case 2:
19042                                         this.viewDate = this.moveYear(this.viewDate, dir);
19043                                         break;
19044                         }
19045                         this.fill();
19046                         break;
19047                     case 'today':
19048                         var date = new Date();
19049                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19050 //                        this.fill()
19051                         this.setValue(this.formatDate(this.date));
19052                         
19053                         this.hide();
19054                         break;
19055                 }
19056                 break;
19057             case 'span':
19058                 if (className.indexOf('disabled') < 0) {
19059                     this.viewDate.setUTCDate(1);
19060                     if (className.indexOf('month') > -1) {
19061                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19062                     } else {
19063                         var year = parseInt(html, 10) || 0;
19064                         this.viewDate.setUTCFullYear(year);
19065                         
19066                     }
19067                     
19068                     if(this.singleMode){
19069                         this.setValue(this.formatDate(this.viewDate));
19070                         this.hide();
19071                         return;
19072                     }
19073                     
19074                     this.showMode(-1);
19075                     this.fill();
19076                 }
19077                 break;
19078                 
19079             case 'td':
19080                 //Roo.log(className);
19081                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19082                     var day = parseInt(html, 10) || 1;
19083                     var year = this.viewDate.getUTCFullYear(),
19084                         month = this.viewDate.getUTCMonth();
19085
19086                     if (className.indexOf('old') > -1) {
19087                         if(month === 0 ){
19088                             month = 11;
19089                             year -= 1;
19090                         }else{
19091                             month -= 1;
19092                         }
19093                     } else if (className.indexOf('new') > -1) {
19094                         if (month == 11) {
19095                             month = 0;
19096                             year += 1;
19097                         } else {
19098                             month += 1;
19099                         }
19100                     }
19101                     //Roo.log([year,month,day]);
19102                     this.date = this.UTCDate(year, month, day,0,0,0,0);
19103                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19104 //                    this.fill();
19105                     //Roo.log(this.formatDate(this.date));
19106                     this.setValue(this.formatDate(this.date));
19107                     this.hide();
19108                 }
19109                 break;
19110         }
19111     },
19112     
19113     setStartDate: function(startDate)
19114     {
19115         this.startDate = startDate || -Infinity;
19116         if (this.startDate !== -Infinity) {
19117             this.startDate = this.parseDate(this.startDate);
19118         }
19119         this.update();
19120         this.updateNavArrows();
19121     },
19122
19123     setEndDate: function(endDate)
19124     {
19125         this.endDate = endDate || Infinity;
19126         if (this.endDate !== Infinity) {
19127             this.endDate = this.parseDate(this.endDate);
19128         }
19129         this.update();
19130         this.updateNavArrows();
19131     },
19132     
19133     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19134     {
19135         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19136         if (typeof(this.daysOfWeekDisabled) !== 'object') {
19137             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19138         }
19139         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19140             return parseInt(d, 10);
19141         });
19142         this.update();
19143         this.updateNavArrows();
19144     },
19145     
19146     updateNavArrows: function() 
19147     {
19148         if(this.singleMode){
19149             return;
19150         }
19151         
19152         var d = new Date(this.viewDate),
19153         year = d.getUTCFullYear(),
19154         month = d.getUTCMonth();
19155         
19156         Roo.each(this.picker().select('.prev', true).elements, function(v){
19157             v.show();
19158             switch (this.viewMode) {
19159                 case 0:
19160
19161                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19162                         v.hide();
19163                     }
19164                     break;
19165                 case 1:
19166                 case 2:
19167                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19168                         v.hide();
19169                     }
19170                     break;
19171             }
19172         });
19173         
19174         Roo.each(this.picker().select('.next', true).elements, function(v){
19175             v.show();
19176             switch (this.viewMode) {
19177                 case 0:
19178
19179                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19180                         v.hide();
19181                     }
19182                     break;
19183                 case 1:
19184                 case 2:
19185                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19186                         v.hide();
19187                     }
19188                     break;
19189             }
19190         })
19191     },
19192     
19193     moveMonth: function(date, dir)
19194     {
19195         if (!dir) {
19196             return date;
19197         }
19198         var new_date = new Date(date.valueOf()),
19199         day = new_date.getUTCDate(),
19200         month = new_date.getUTCMonth(),
19201         mag = Math.abs(dir),
19202         new_month, test;
19203         dir = dir > 0 ? 1 : -1;
19204         if (mag == 1){
19205             test = dir == -1
19206             // If going back one month, make sure month is not current month
19207             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19208             ? function(){
19209                 return new_date.getUTCMonth() == month;
19210             }
19211             // If going forward one month, make sure month is as expected
19212             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19213             : function(){
19214                 return new_date.getUTCMonth() != new_month;
19215             };
19216             new_month = month + dir;
19217             new_date.setUTCMonth(new_month);
19218             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19219             if (new_month < 0 || new_month > 11) {
19220                 new_month = (new_month + 12) % 12;
19221             }
19222         } else {
19223             // For magnitudes >1, move one month at a time...
19224             for (var i=0; i<mag; i++) {
19225                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19226                 new_date = this.moveMonth(new_date, dir);
19227             }
19228             // ...then reset the day, keeping it in the new month
19229             new_month = new_date.getUTCMonth();
19230             new_date.setUTCDate(day);
19231             test = function(){
19232                 return new_month != new_date.getUTCMonth();
19233             };
19234         }
19235         // Common date-resetting loop -- if date is beyond end of month, make it
19236         // end of month
19237         while (test()){
19238             new_date.setUTCDate(--day);
19239             new_date.setUTCMonth(new_month);
19240         }
19241         return new_date;
19242     },
19243
19244     moveYear: function(date, dir)
19245     {
19246         return this.moveMonth(date, dir*12);
19247     },
19248
19249     dateWithinRange: function(date)
19250     {
19251         return date >= this.startDate && date <= this.endDate;
19252     },
19253
19254     
19255     remove: function() 
19256     {
19257         this.picker().remove();
19258     },
19259     
19260     validateValue : function(value)
19261     {
19262         if(this.getVisibilityEl().hasClass('hidden')){
19263             return true;
19264         }
19265         
19266         if(value.length < 1)  {
19267             if(this.allowBlank){
19268                 return true;
19269             }
19270             return false;
19271         }
19272         
19273         if(value.length < this.minLength){
19274             return false;
19275         }
19276         if(value.length > this.maxLength){
19277             return false;
19278         }
19279         if(this.vtype){
19280             var vt = Roo.form.VTypes;
19281             if(!vt[this.vtype](value, this)){
19282                 return false;
19283             }
19284         }
19285         if(typeof this.validator == "function"){
19286             var msg = this.validator(value);
19287             if(msg !== true){
19288                 return false;
19289             }
19290         }
19291         
19292         if(this.regex && !this.regex.test(value)){
19293             return false;
19294         }
19295         
19296         if(typeof(this.parseDate(value)) == 'undefined'){
19297             return false;
19298         }
19299         
19300         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19301             return false;
19302         }      
19303         
19304         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19305             return false;
19306         } 
19307         
19308         
19309         return true;
19310     },
19311     
19312     reset : function()
19313     {
19314         this.date = this.viewDate = '';
19315         
19316         Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19317     },
19318     
19319     setVisible : function(visible)
19320     {
19321         if(!this.getEl()){
19322             return;
19323         }
19324         
19325         this.getEl().removeClass('hidden');
19326         
19327         if(visible){
19328             this.fireEvent('show', this);
19329             return;
19330         }
19331         
19332         this.getEl().addClass('hidden');
19333         this.fireEvent('hide', this);
19334     }
19335    
19336 });
19337
19338 Roo.apply(Roo.bootstrap.DateField,  {
19339     
19340     head : {
19341         tag: 'thead',
19342         cn: [
19343         {
19344             tag: 'tr',
19345             cn: [
19346             {
19347                 tag: 'th',
19348                 cls: 'prev',
19349                 html: '<i class="fa fa-arrow-left"/>'
19350             },
19351             {
19352                 tag: 'th',
19353                 cls: 'switch',
19354                 colspan: '5'
19355             },
19356             {
19357                 tag: 'th',
19358                 cls: 'next',
19359                 html: '<i class="fa fa-arrow-right"/>'
19360             }
19361
19362             ]
19363         }
19364         ]
19365     },
19366     
19367     content : {
19368         tag: 'tbody',
19369         cn: [
19370         {
19371             tag: 'tr',
19372             cn: [
19373             {
19374                 tag: 'td',
19375                 colspan: '7'
19376             }
19377             ]
19378         }
19379         ]
19380     },
19381     
19382     footer : {
19383         tag: 'tfoot',
19384         cn: [
19385         {
19386             tag: 'tr',
19387             cn: [
19388             {
19389                 tag: 'th',
19390                 colspan: '7',
19391                 cls: 'today'
19392             }
19393                     
19394             ]
19395         }
19396         ]
19397     },
19398     
19399     dates:{
19400         en: {
19401             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19402             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19403             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19404             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19405             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19406             today: "Today"
19407         }
19408     },
19409     
19410     modes: [
19411     {
19412         clsName: 'days',
19413         navFnc: 'Month',
19414         navStep: 1
19415     },
19416     {
19417         clsName: 'months',
19418         navFnc: 'FullYear',
19419         navStep: 1
19420     },
19421     {
19422         clsName: 'years',
19423         navFnc: 'FullYear',
19424         navStep: 10
19425     }]
19426 });
19427
19428 Roo.apply(Roo.bootstrap.DateField,  {
19429   
19430     template : {
19431         tag: 'div',
19432         cls: 'datepicker dropdown-menu roo-dynamic',
19433         cn: [
19434         {
19435             tag: 'div',
19436             cls: 'datepicker-days',
19437             cn: [
19438             {
19439                 tag: 'table',
19440                 cls: 'table-condensed',
19441                 cn:[
19442                 Roo.bootstrap.DateField.head,
19443                 {
19444                     tag: 'tbody'
19445                 },
19446                 Roo.bootstrap.DateField.footer
19447                 ]
19448             }
19449             ]
19450         },
19451         {
19452             tag: 'div',
19453             cls: 'datepicker-months',
19454             cn: [
19455             {
19456                 tag: 'table',
19457                 cls: 'table-condensed',
19458                 cn:[
19459                 Roo.bootstrap.DateField.head,
19460                 Roo.bootstrap.DateField.content,
19461                 Roo.bootstrap.DateField.footer
19462                 ]
19463             }
19464             ]
19465         },
19466         {
19467             tag: 'div',
19468             cls: 'datepicker-years',
19469             cn: [
19470             {
19471                 tag: 'table',
19472                 cls: 'table-condensed',
19473                 cn:[
19474                 Roo.bootstrap.DateField.head,
19475                 Roo.bootstrap.DateField.content,
19476                 Roo.bootstrap.DateField.footer
19477                 ]
19478             }
19479             ]
19480         }
19481         ]
19482     }
19483 });
19484
19485  
19486
19487  /*
19488  * - LGPL
19489  *
19490  * TimeField
19491  * 
19492  */
19493
19494 /**
19495  * @class Roo.bootstrap.TimeField
19496  * @extends Roo.bootstrap.Input
19497  * Bootstrap DateField class
19498  * 
19499  * 
19500  * @constructor
19501  * Create a new TimeField
19502  * @param {Object} config The config object
19503  */
19504
19505 Roo.bootstrap.TimeField = function(config){
19506     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19507     this.addEvents({
19508             /**
19509              * @event show
19510              * Fires when this field show.
19511              * @param {Roo.bootstrap.DateField} thisthis
19512              * @param {Mixed} date The date value
19513              */
19514             show : true,
19515             /**
19516              * @event show
19517              * Fires when this field hide.
19518              * @param {Roo.bootstrap.DateField} this
19519              * @param {Mixed} date The date value
19520              */
19521             hide : true,
19522             /**
19523              * @event select
19524              * Fires when select a date.
19525              * @param {Roo.bootstrap.DateField} this
19526              * @param {Mixed} date The date value
19527              */
19528             select : true
19529         });
19530 };
19531
19532 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19533     
19534     /**
19535      * @cfg {String} format
19536      * The default time format string which can be overriden for localization support.  The format must be
19537      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19538      */
19539     format : "H:i",
19540        
19541     onRender: function(ct, position)
19542     {
19543         
19544         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19545                 
19546         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19547         
19548         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19549         
19550         this.pop = this.picker().select('>.datepicker-time',true).first();
19551         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19552         
19553         this.picker().on('mousedown', this.onMousedown, this);
19554         this.picker().on('click', this.onClick, this);
19555         
19556         this.picker().addClass('datepicker-dropdown');
19557     
19558         this.fillTime();
19559         this.update();
19560             
19561         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19562         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19563         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19564         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19565         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19566         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19567
19568     },
19569     
19570     fireKey: function(e){
19571         if (!this.picker().isVisible()){
19572             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19573                 this.show();
19574             }
19575             return;
19576         }
19577
19578         e.preventDefault();
19579         
19580         switch(e.keyCode){
19581             case 27: // escape
19582                 this.hide();
19583                 break;
19584             case 37: // left
19585             case 39: // right
19586                 this.onTogglePeriod();
19587                 break;
19588             case 38: // up
19589                 this.onIncrementMinutes();
19590                 break;
19591             case 40: // down
19592                 this.onDecrementMinutes();
19593                 break;
19594             case 13: // enter
19595             case 9: // tab
19596                 this.setTime();
19597                 break;
19598         }
19599     },
19600     
19601     onClick: function(e) {
19602         e.stopPropagation();
19603         e.preventDefault();
19604     },
19605     
19606     picker : function()
19607     {
19608         return this.el.select('.datepicker', true).first();
19609     },
19610     
19611     fillTime: function()
19612     {    
19613         var time = this.pop.select('tbody', true).first();
19614         
19615         time.dom.innerHTML = '';
19616         
19617         time.createChild({
19618             tag: 'tr',
19619             cn: [
19620                 {
19621                     tag: 'td',
19622                     cn: [
19623                         {
19624                             tag: 'a',
19625                             href: '#',
19626                             cls: 'btn',
19627                             cn: [
19628                                 {
19629                                     tag: 'span',
19630                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19631                                 }
19632                             ]
19633                         } 
19634                     ]
19635                 },
19636                 {
19637                     tag: 'td',
19638                     cls: 'separator'
19639                 },
19640                 {
19641                     tag: 'td',
19642                     cn: [
19643                         {
19644                             tag: 'a',
19645                             href: '#',
19646                             cls: 'btn',
19647                             cn: [
19648                                 {
19649                                     tag: 'span',
19650                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19651                                 }
19652                             ]
19653                         }
19654                     ]
19655                 },
19656                 {
19657                     tag: 'td',
19658                     cls: 'separator'
19659                 }
19660             ]
19661         });
19662         
19663         time.createChild({
19664             tag: 'tr',
19665             cn: [
19666                 {
19667                     tag: 'td',
19668                     cn: [
19669                         {
19670                             tag: 'span',
19671                             cls: 'timepicker-hour',
19672                             html: '00'
19673                         }  
19674                     ]
19675                 },
19676                 {
19677                     tag: 'td',
19678                     cls: 'separator',
19679                     html: ':'
19680                 },
19681                 {
19682                     tag: 'td',
19683                     cn: [
19684                         {
19685                             tag: 'span',
19686                             cls: 'timepicker-minute',
19687                             html: '00'
19688                         }  
19689                     ]
19690                 },
19691                 {
19692                     tag: 'td',
19693                     cls: 'separator'
19694                 },
19695                 {
19696                     tag: 'td',
19697                     cn: [
19698                         {
19699                             tag: 'button',
19700                             type: 'button',
19701                             cls: 'btn btn-primary period',
19702                             html: 'AM'
19703                             
19704                         }
19705                     ]
19706                 }
19707             ]
19708         });
19709         
19710         time.createChild({
19711             tag: 'tr',
19712             cn: [
19713                 {
19714                     tag: 'td',
19715                     cn: [
19716                         {
19717                             tag: 'a',
19718                             href: '#',
19719                             cls: 'btn',
19720                             cn: [
19721                                 {
19722                                     tag: 'span',
19723                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19724                                 }
19725                             ]
19726                         }
19727                     ]
19728                 },
19729                 {
19730                     tag: 'td',
19731                     cls: 'separator'
19732                 },
19733                 {
19734                     tag: 'td',
19735                     cn: [
19736                         {
19737                             tag: 'a',
19738                             href: '#',
19739                             cls: 'btn',
19740                             cn: [
19741                                 {
19742                                     tag: 'span',
19743                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19744                                 }
19745                             ]
19746                         }
19747                     ]
19748                 },
19749                 {
19750                     tag: 'td',
19751                     cls: 'separator'
19752                 }
19753             ]
19754         });
19755         
19756     },
19757     
19758     update: function()
19759     {
19760         
19761         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19762         
19763         this.fill();
19764     },
19765     
19766     fill: function() 
19767     {
19768         var hours = this.time.getHours();
19769         var minutes = this.time.getMinutes();
19770         var period = 'AM';
19771         
19772         if(hours > 11){
19773             period = 'PM';
19774         }
19775         
19776         if(hours == 0){
19777             hours = 12;
19778         }
19779         
19780         
19781         if(hours > 12){
19782             hours = hours - 12;
19783         }
19784         
19785         if(hours < 10){
19786             hours = '0' + hours;
19787         }
19788         
19789         if(minutes < 10){
19790             minutes = '0' + minutes;
19791         }
19792         
19793         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19794         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19795         this.pop.select('button', true).first().dom.innerHTML = period;
19796         
19797     },
19798     
19799     place: function()
19800     {   
19801         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19802         
19803         var cls = ['bottom'];
19804         
19805         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19806             cls.pop();
19807             cls.push('top');
19808         }
19809         
19810         cls.push('right');
19811         
19812         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19813             cls.pop();
19814             cls.push('left');
19815         }
19816         
19817         this.picker().addClass(cls.join('-'));
19818         
19819         var _this = this;
19820         
19821         Roo.each(cls, function(c){
19822             if(c == 'bottom'){
19823                 _this.picker().setTop(_this.inputEl().getHeight());
19824                 return;
19825             }
19826             if(c == 'top'){
19827                 _this.picker().setTop(0 - _this.picker().getHeight());
19828                 return;
19829             }
19830             
19831             if(c == 'left'){
19832                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19833                 return;
19834             }
19835             if(c == 'right'){
19836                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19837                 return;
19838             }
19839         });
19840         
19841     },
19842   
19843     onFocus : function()
19844     {
19845         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19846         this.show();
19847     },
19848     
19849     onBlur : function()
19850     {
19851         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19852         this.hide();
19853     },
19854     
19855     show : function()
19856     {
19857         this.picker().show();
19858         this.pop.show();
19859         this.update();
19860         this.place();
19861         
19862         this.fireEvent('show', this, this.date);
19863     },
19864     
19865     hide : function()
19866     {
19867         this.picker().hide();
19868         this.pop.hide();
19869         
19870         this.fireEvent('hide', this, this.date);
19871     },
19872     
19873     setTime : function()
19874     {
19875         this.hide();
19876         this.setValue(this.time.format(this.format));
19877         
19878         this.fireEvent('select', this, this.date);
19879         
19880         
19881     },
19882     
19883     onMousedown: function(e){
19884         e.stopPropagation();
19885         e.preventDefault();
19886     },
19887     
19888     onIncrementHours: function()
19889     {
19890         Roo.log('onIncrementHours');
19891         this.time = this.time.add(Date.HOUR, 1);
19892         this.update();
19893         
19894     },
19895     
19896     onDecrementHours: function()
19897     {
19898         Roo.log('onDecrementHours');
19899         this.time = this.time.add(Date.HOUR, -1);
19900         this.update();
19901     },
19902     
19903     onIncrementMinutes: function()
19904     {
19905         Roo.log('onIncrementMinutes');
19906         this.time = this.time.add(Date.MINUTE, 1);
19907         this.update();
19908     },
19909     
19910     onDecrementMinutes: function()
19911     {
19912         Roo.log('onDecrementMinutes');
19913         this.time = this.time.add(Date.MINUTE, -1);
19914         this.update();
19915     },
19916     
19917     onTogglePeriod: function()
19918     {
19919         Roo.log('onTogglePeriod');
19920         this.time = this.time.add(Date.HOUR, 12);
19921         this.update();
19922     }
19923     
19924    
19925 });
19926
19927 Roo.apply(Roo.bootstrap.TimeField,  {
19928     
19929     content : {
19930         tag: 'tbody',
19931         cn: [
19932             {
19933                 tag: 'tr',
19934                 cn: [
19935                 {
19936                     tag: 'td',
19937                     colspan: '7'
19938                 }
19939                 ]
19940             }
19941         ]
19942     },
19943     
19944     footer : {
19945         tag: 'tfoot',
19946         cn: [
19947             {
19948                 tag: 'tr',
19949                 cn: [
19950                 {
19951                     tag: 'th',
19952                     colspan: '7',
19953                     cls: '',
19954                     cn: [
19955                         {
19956                             tag: 'button',
19957                             cls: 'btn btn-info ok',
19958                             html: 'OK'
19959                         }
19960                     ]
19961                 }
19962
19963                 ]
19964             }
19965         ]
19966     }
19967 });
19968
19969 Roo.apply(Roo.bootstrap.TimeField,  {
19970   
19971     template : {
19972         tag: 'div',
19973         cls: 'datepicker dropdown-menu',
19974         cn: [
19975             {
19976                 tag: 'div',
19977                 cls: 'datepicker-time',
19978                 cn: [
19979                 {
19980                     tag: 'table',
19981                     cls: 'table-condensed',
19982                     cn:[
19983                     Roo.bootstrap.TimeField.content,
19984                     Roo.bootstrap.TimeField.footer
19985                     ]
19986                 }
19987                 ]
19988             }
19989         ]
19990     }
19991 });
19992
19993  
19994
19995  /*
19996  * - LGPL
19997  *
19998  * MonthField
19999  * 
20000  */
20001
20002 /**
20003  * @class Roo.bootstrap.MonthField
20004  * @extends Roo.bootstrap.Input
20005  * Bootstrap MonthField class
20006  * 
20007  * @cfg {String} language default en
20008  * 
20009  * @constructor
20010  * Create a new MonthField
20011  * @param {Object} config The config object
20012  */
20013
20014 Roo.bootstrap.MonthField = function(config){
20015     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20016     
20017     this.addEvents({
20018         /**
20019          * @event show
20020          * Fires when this field show.
20021          * @param {Roo.bootstrap.MonthField} this
20022          * @param {Mixed} date The date value
20023          */
20024         show : true,
20025         /**
20026          * @event show
20027          * Fires when this field hide.
20028          * @param {Roo.bootstrap.MonthField} this
20029          * @param {Mixed} date The date value
20030          */
20031         hide : true,
20032         /**
20033          * @event select
20034          * Fires when select a date.
20035          * @param {Roo.bootstrap.MonthField} this
20036          * @param {String} oldvalue The old value
20037          * @param {String} newvalue The new value
20038          */
20039         select : true
20040     });
20041 };
20042
20043 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
20044     
20045     onRender: function(ct, position)
20046     {
20047         
20048         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20049         
20050         this.language = this.language || 'en';
20051         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20052         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20053         
20054         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20055         this.isInline = false;
20056         this.isInput = true;
20057         this.component = this.el.select('.add-on', true).first() || false;
20058         this.component = (this.component && this.component.length === 0) ? false : this.component;
20059         this.hasInput = this.component && this.inputEL().length;
20060         
20061         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20062         
20063         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20064         
20065         this.picker().on('mousedown', this.onMousedown, this);
20066         this.picker().on('click', this.onClick, this);
20067         
20068         this.picker().addClass('datepicker-dropdown');
20069         
20070         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20071             v.setStyle('width', '189px');
20072         });
20073         
20074         this.fillMonths();
20075         
20076         this.update();
20077         
20078         if(this.isInline) {
20079             this.show();
20080         }
20081         
20082     },
20083     
20084     setValue: function(v, suppressEvent)
20085     {   
20086         var o = this.getValue();
20087         
20088         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20089         
20090         this.update();
20091
20092         if(suppressEvent !== true){
20093             this.fireEvent('select', this, o, v);
20094         }
20095         
20096     },
20097     
20098     getValue: function()
20099     {
20100         return this.value;
20101     },
20102     
20103     onClick: function(e) 
20104     {
20105         e.stopPropagation();
20106         e.preventDefault();
20107         
20108         var target = e.getTarget();
20109         
20110         if(target.nodeName.toLowerCase() === 'i'){
20111             target = Roo.get(target).dom.parentNode;
20112         }
20113         
20114         var nodeName = target.nodeName;
20115         var className = target.className;
20116         var html = target.innerHTML;
20117         
20118         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20119             return;
20120         }
20121         
20122         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20123         
20124         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20125         
20126         this.hide();
20127                         
20128     },
20129     
20130     picker : function()
20131     {
20132         return this.pickerEl;
20133     },
20134     
20135     fillMonths: function()
20136     {    
20137         var i = 0;
20138         var months = this.picker().select('>.datepicker-months td', true).first();
20139         
20140         months.dom.innerHTML = '';
20141         
20142         while (i < 12) {
20143             var month = {
20144                 tag: 'span',
20145                 cls: 'month',
20146                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20147             };
20148             
20149             months.createChild(month);
20150         }
20151         
20152     },
20153     
20154     update: function()
20155     {
20156         var _this = this;
20157         
20158         if(typeof(this.vIndex) == 'undefined' && this.value.length){
20159             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20160         }
20161         
20162         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20163             e.removeClass('active');
20164             
20165             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20166                 e.addClass('active');
20167             }
20168         })
20169     },
20170     
20171     place: function()
20172     {
20173         if(this.isInline) {
20174             return;
20175         }
20176         
20177         this.picker().removeClass(['bottom', 'top']);
20178         
20179         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20180             /*
20181              * place to the top of element!
20182              *
20183              */
20184             
20185             this.picker().addClass('top');
20186             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20187             
20188             return;
20189         }
20190         
20191         this.picker().addClass('bottom');
20192         
20193         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20194     },
20195     
20196     onFocus : function()
20197     {
20198         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20199         this.show();
20200     },
20201     
20202     onBlur : function()
20203     {
20204         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20205         
20206         var d = this.inputEl().getValue();
20207         
20208         this.setValue(d);
20209                 
20210         this.hide();
20211     },
20212     
20213     show : function()
20214     {
20215         this.picker().show();
20216         this.picker().select('>.datepicker-months', true).first().show();
20217         this.update();
20218         this.place();
20219         
20220         this.fireEvent('show', this, this.date);
20221     },
20222     
20223     hide : function()
20224     {
20225         if(this.isInline) {
20226             return;
20227         }
20228         this.picker().hide();
20229         this.fireEvent('hide', this, this.date);
20230         
20231     },
20232     
20233     onMousedown: function(e)
20234     {
20235         e.stopPropagation();
20236         e.preventDefault();
20237     },
20238     
20239     keyup: function(e)
20240     {
20241         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20242         this.update();
20243     },
20244
20245     fireKey: function(e)
20246     {
20247         if (!this.picker().isVisible()){
20248             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20249                 this.show();
20250             }
20251             return;
20252         }
20253         
20254         var dir;
20255         
20256         switch(e.keyCode){
20257             case 27: // escape
20258                 this.hide();
20259                 e.preventDefault();
20260                 break;
20261             case 37: // left
20262             case 39: // right
20263                 dir = e.keyCode == 37 ? -1 : 1;
20264                 
20265                 this.vIndex = this.vIndex + dir;
20266                 
20267                 if(this.vIndex < 0){
20268                     this.vIndex = 0;
20269                 }
20270                 
20271                 if(this.vIndex > 11){
20272                     this.vIndex = 11;
20273                 }
20274                 
20275                 if(isNaN(this.vIndex)){
20276                     this.vIndex = 0;
20277                 }
20278                 
20279                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20280                 
20281                 break;
20282             case 38: // up
20283             case 40: // down
20284                 
20285                 dir = e.keyCode == 38 ? -1 : 1;
20286                 
20287                 this.vIndex = this.vIndex + dir * 4;
20288                 
20289                 if(this.vIndex < 0){
20290                     this.vIndex = 0;
20291                 }
20292                 
20293                 if(this.vIndex > 11){
20294                     this.vIndex = 11;
20295                 }
20296                 
20297                 if(isNaN(this.vIndex)){
20298                     this.vIndex = 0;
20299                 }
20300                 
20301                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20302                 break;
20303                 
20304             case 13: // enter
20305                 
20306                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20307                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20308                 }
20309                 
20310                 this.hide();
20311                 e.preventDefault();
20312                 break;
20313             case 9: // tab
20314                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20315                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20316                 }
20317                 this.hide();
20318                 break;
20319             case 16: // shift
20320             case 17: // ctrl
20321             case 18: // alt
20322                 break;
20323             default :
20324                 this.hide();
20325                 
20326         }
20327     },
20328     
20329     remove: function() 
20330     {
20331         this.picker().remove();
20332     }
20333    
20334 });
20335
20336 Roo.apply(Roo.bootstrap.MonthField,  {
20337     
20338     content : {
20339         tag: 'tbody',
20340         cn: [
20341         {
20342             tag: 'tr',
20343             cn: [
20344             {
20345                 tag: 'td',
20346                 colspan: '7'
20347             }
20348             ]
20349         }
20350         ]
20351     },
20352     
20353     dates:{
20354         en: {
20355             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20356             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20357         }
20358     }
20359 });
20360
20361 Roo.apply(Roo.bootstrap.MonthField,  {
20362   
20363     template : {
20364         tag: 'div',
20365         cls: 'datepicker dropdown-menu roo-dynamic',
20366         cn: [
20367             {
20368                 tag: 'div',
20369                 cls: 'datepicker-months',
20370                 cn: [
20371                 {
20372                     tag: 'table',
20373                     cls: 'table-condensed',
20374                     cn:[
20375                         Roo.bootstrap.DateField.content
20376                     ]
20377                 }
20378                 ]
20379             }
20380         ]
20381     }
20382 });
20383
20384  
20385
20386  
20387  /*
20388  * - LGPL
20389  *
20390  * CheckBox
20391  * 
20392  */
20393
20394 /**
20395  * @class Roo.bootstrap.CheckBox
20396  * @extends Roo.bootstrap.Input
20397  * Bootstrap CheckBox class
20398  * 
20399  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20400  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20401  * @cfg {String} boxLabel The text that appears beside the checkbox
20402  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20403  * @cfg {Boolean} checked initnal the element
20404  * @cfg {Boolean} inline inline the element (default false)
20405  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20406  * @cfg {String} tooltip label tooltip
20407  * 
20408  * @constructor
20409  * Create a new CheckBox
20410  * @param {Object} config The config object
20411  */
20412
20413 Roo.bootstrap.CheckBox = function(config){
20414     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20415    
20416     this.addEvents({
20417         /**
20418         * @event check
20419         * Fires when the element is checked or unchecked.
20420         * @param {Roo.bootstrap.CheckBox} this This input
20421         * @param {Boolean} checked The new checked value
20422         */
20423        check : true,
20424        /**
20425         * @event click
20426         * Fires when the element is click.
20427         * @param {Roo.bootstrap.CheckBox} this This input
20428         */
20429        click : true
20430     });
20431     
20432 };
20433
20434 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20435   
20436     inputType: 'checkbox',
20437     inputValue: 1,
20438     valueOff: 0,
20439     boxLabel: false,
20440     checked: false,
20441     weight : false,
20442     inline: false,
20443     tooltip : '',
20444     
20445     getAutoCreate : function()
20446     {
20447         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20448         
20449         var id = Roo.id();
20450         
20451         var cfg = {};
20452         
20453         cfg.cls = 'form-group ' + this.inputType; //input-group
20454         
20455         if(this.inline){
20456             cfg.cls += ' ' + this.inputType + '-inline';
20457         }
20458         
20459         var input =  {
20460             tag: 'input',
20461             id : id,
20462             type : this.inputType,
20463             value : this.inputValue,
20464             cls : 'roo-' + this.inputType, //'form-box',
20465             placeholder : this.placeholder || ''
20466             
20467         };
20468         
20469         if(this.inputType != 'radio'){
20470             var hidden =  {
20471                 tag: 'input',
20472                 type : 'hidden',
20473                 cls : 'roo-hidden-value',
20474                 value : this.checked ? this.inputValue : this.valueOff
20475             };
20476         }
20477         
20478             
20479         if (this.weight) { // Validity check?
20480             cfg.cls += " " + this.inputType + "-" + this.weight;
20481         }
20482         
20483         if (this.disabled) {
20484             input.disabled=true;
20485         }
20486         
20487         if(this.checked){
20488             input.checked = this.checked;
20489         }
20490         
20491         if (this.name) {
20492             
20493             input.name = this.name;
20494             
20495             if(this.inputType != 'radio'){
20496                 hidden.name = this.name;
20497                 input.name = '_hidden_' + this.name;
20498             }
20499         }
20500         
20501         if (this.size) {
20502             input.cls += ' input-' + this.size;
20503         }
20504         
20505         var settings=this;
20506         
20507         ['xs','sm','md','lg'].map(function(size){
20508             if (settings[size]) {
20509                 cfg.cls += ' col-' + size + '-' + settings[size];
20510             }
20511         });
20512         
20513         var inputblock = input;
20514          
20515         if (this.before || this.after) {
20516             
20517             inputblock = {
20518                 cls : 'input-group',
20519                 cn :  [] 
20520             };
20521             
20522             if (this.before) {
20523                 inputblock.cn.push({
20524                     tag :'span',
20525                     cls : 'input-group-addon',
20526                     html : this.before
20527                 });
20528             }
20529             
20530             inputblock.cn.push(input);
20531             
20532             if(this.inputType != 'radio'){
20533                 inputblock.cn.push(hidden);
20534             }
20535             
20536             if (this.after) {
20537                 inputblock.cn.push({
20538                     tag :'span',
20539                     cls : 'input-group-addon',
20540                     html : this.after
20541                 });
20542             }
20543             
20544         }
20545         
20546         if (align ==='left' && this.fieldLabel.length) {
20547 //                Roo.log("left and has label");
20548             cfg.cn = [
20549                 {
20550                     tag: 'label',
20551                     'for' :  id,
20552                     cls : 'control-label',
20553                     html : this.fieldLabel
20554                 },
20555                 {
20556                     cls : "", 
20557                     cn: [
20558                         inputblock
20559                     ]
20560                 }
20561             ];
20562             
20563             if(this.labelWidth > 12){
20564                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20565             }
20566             
20567             if(this.labelWidth < 13 && this.labelmd == 0){
20568                 this.labelmd = this.labelWidth;
20569             }
20570             
20571             if(this.labellg > 0){
20572                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20573                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20574             }
20575             
20576             if(this.labelmd > 0){
20577                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20578                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20579             }
20580             
20581             if(this.labelsm > 0){
20582                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20583                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20584             }
20585             
20586             if(this.labelxs > 0){
20587                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20588                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20589             }
20590             
20591         } else if ( this.fieldLabel.length) {
20592 //                Roo.log(" label");
20593                 cfg.cn = [
20594                    
20595                     {
20596                         tag: this.boxLabel ? 'span' : 'label',
20597                         'for': id,
20598                         cls: 'control-label box-input-label',
20599                         //cls : 'input-group-addon',
20600                         html : this.fieldLabel
20601                     },
20602                     
20603                     inputblock
20604                     
20605                 ];
20606
20607         } else {
20608             
20609 //                Roo.log(" no label && no align");
20610                 cfg.cn = [  inputblock ] ;
20611                 
20612                 
20613         }
20614         
20615         if(this.boxLabel){
20616              var boxLabelCfg = {
20617                 tag: 'label',
20618                 //'for': id, // box label is handled by onclick - so no for...
20619                 cls: 'box-label',
20620                 html: this.boxLabel
20621             };
20622             
20623             if(this.tooltip){
20624                 boxLabelCfg.tooltip = this.tooltip;
20625             }
20626              
20627             cfg.cn.push(boxLabelCfg);
20628         }
20629         
20630         if(this.inputType != 'radio'){
20631             cfg.cn.push(hidden);
20632         }
20633         
20634         return cfg;
20635         
20636     },
20637     
20638     /**
20639      * return the real input element.
20640      */
20641     inputEl: function ()
20642     {
20643         return this.el.select('input.roo-' + this.inputType,true).first();
20644     },
20645     hiddenEl: function ()
20646     {
20647         return this.el.select('input.roo-hidden-value',true).first();
20648     },
20649     
20650     labelEl: function()
20651     {
20652         return this.el.select('label.control-label',true).first();
20653     },
20654     /* depricated... */
20655     
20656     label: function()
20657     {
20658         return this.labelEl();
20659     },
20660     
20661     boxLabelEl: function()
20662     {
20663         return this.el.select('label.box-label',true).first();
20664     },
20665     
20666     initEvents : function()
20667     {
20668 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20669         
20670         this.inputEl().on('click', this.onClick,  this);
20671         
20672         if (this.boxLabel) { 
20673             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20674         }
20675         
20676         this.startValue = this.getValue();
20677         
20678         if(this.groupId){
20679             Roo.bootstrap.CheckBox.register(this);
20680         }
20681     },
20682     
20683     onClick : function(e)
20684     {   
20685         if(this.fireEvent('click', this, e) !== false){
20686             this.setChecked(!this.checked);
20687         }
20688         
20689     },
20690     
20691     setChecked : function(state,suppressEvent)
20692     {
20693         this.startValue = this.getValue();
20694
20695         if(this.inputType == 'radio'){
20696             
20697             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20698                 e.dom.checked = false;
20699             });
20700             
20701             this.inputEl().dom.checked = true;
20702             
20703             this.inputEl().dom.value = this.inputValue;
20704             
20705             if(suppressEvent !== true){
20706                 this.fireEvent('check', this, true);
20707             }
20708             
20709             this.validate();
20710             
20711             return;
20712         }
20713         
20714         this.checked = state;
20715         
20716         this.inputEl().dom.checked = state;
20717         
20718         
20719         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20720         
20721         if(suppressEvent !== true){
20722             this.fireEvent('check', this, state);
20723         }
20724         
20725         this.validate();
20726     },
20727     
20728     getValue : function()
20729     {
20730         if(this.inputType == 'radio'){
20731             return this.getGroupValue();
20732         }
20733         
20734         return this.hiddenEl().dom.value;
20735         
20736     },
20737     
20738     getGroupValue : function()
20739     {
20740         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20741             return '';
20742         }
20743         
20744         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20745     },
20746     
20747     setValue : function(v,suppressEvent)
20748     {
20749         if(this.inputType == 'radio'){
20750             this.setGroupValue(v, suppressEvent);
20751             return;
20752         }
20753         
20754         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20755         
20756         this.validate();
20757     },
20758     
20759     setGroupValue : function(v, suppressEvent)
20760     {
20761         this.startValue = this.getValue();
20762         
20763         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20764             e.dom.checked = false;
20765             
20766             if(e.dom.value == v){
20767                 e.dom.checked = true;
20768             }
20769         });
20770         
20771         if(suppressEvent !== true){
20772             this.fireEvent('check', this, true);
20773         }
20774
20775         this.validate();
20776         
20777         return;
20778     },
20779     
20780     validate : function()
20781     {
20782         if(this.getVisibilityEl().hasClass('hidden')){
20783             return true;
20784         }
20785         
20786         if(
20787                 this.disabled || 
20788                 (this.inputType == 'radio' && this.validateRadio()) ||
20789                 (this.inputType == 'checkbox' && this.validateCheckbox())
20790         ){
20791             this.markValid();
20792             return true;
20793         }
20794         
20795         this.markInvalid();
20796         return false;
20797     },
20798     
20799     validateRadio : function()
20800     {
20801         if(this.getVisibilityEl().hasClass('hidden')){
20802             return true;
20803         }
20804         
20805         if(this.allowBlank){
20806             return true;
20807         }
20808         
20809         var valid = false;
20810         
20811         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20812             if(!e.dom.checked){
20813                 return;
20814             }
20815             
20816             valid = true;
20817             
20818             return false;
20819         });
20820         
20821         return valid;
20822     },
20823     
20824     validateCheckbox : function()
20825     {
20826         if(!this.groupId){
20827             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20828             //return (this.getValue() == this.inputValue) ? true : false;
20829         }
20830         
20831         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20832         
20833         if(!group){
20834             return false;
20835         }
20836         
20837         var r = false;
20838         
20839         for(var i in group){
20840             if(group[i].el.isVisible(true)){
20841                 r = false;
20842                 break;
20843             }
20844             
20845             r = true;
20846         }
20847         
20848         for(var i in group){
20849             if(r){
20850                 break;
20851             }
20852             
20853             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20854         }
20855         
20856         return r;
20857     },
20858     
20859     /**
20860      * Mark this field as valid
20861      */
20862     markValid : function()
20863     {
20864         var _this = this;
20865         
20866         this.fireEvent('valid', this);
20867         
20868         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20869         
20870         if(this.groupId){
20871             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20872         }
20873         
20874         if(label){
20875             label.markValid();
20876         }
20877
20878         if(this.inputType == 'radio'){
20879             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20880                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20881                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20882             });
20883             
20884             return;
20885         }
20886
20887         if(!this.groupId){
20888             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20889             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20890             return;
20891         }
20892         
20893         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20894         
20895         if(!group){
20896             return;
20897         }
20898         
20899         for(var i in group){
20900             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20901             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20902         }
20903     },
20904     
20905      /**
20906      * Mark this field as invalid
20907      * @param {String} msg The validation message
20908      */
20909     markInvalid : function(msg)
20910     {
20911         if(this.allowBlank){
20912             return;
20913         }
20914         
20915         var _this = this;
20916         
20917         this.fireEvent('invalid', this, msg);
20918         
20919         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20920         
20921         if(this.groupId){
20922             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20923         }
20924         
20925         if(label){
20926             label.markInvalid();
20927         }
20928             
20929         if(this.inputType == 'radio'){
20930             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20931                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20932                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20933             });
20934             
20935             return;
20936         }
20937         
20938         if(!this.groupId){
20939             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20940             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20941             return;
20942         }
20943         
20944         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20945         
20946         if(!group){
20947             return;
20948         }
20949         
20950         for(var i in group){
20951             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20952             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20953         }
20954         
20955     },
20956     
20957     clearInvalid : function()
20958     {
20959         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20960         
20961         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20962         
20963         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20964         
20965         if (label && label.iconEl) {
20966             label.iconEl.removeClass(label.validClass);
20967             label.iconEl.removeClass(label.invalidClass);
20968         }
20969     },
20970     
20971     disable : function()
20972     {
20973         if(this.inputType != 'radio'){
20974             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20975             return;
20976         }
20977         
20978         var _this = this;
20979         
20980         if(this.rendered){
20981             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20982                 _this.getActionEl().addClass(this.disabledClass);
20983                 e.dom.disabled = true;
20984             });
20985         }
20986         
20987         this.disabled = true;
20988         this.fireEvent("disable", this);
20989         return this;
20990     },
20991
20992     enable : function()
20993     {
20994         if(this.inputType != 'radio'){
20995             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20996             return;
20997         }
20998         
20999         var _this = this;
21000         
21001         if(this.rendered){
21002             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21003                 _this.getActionEl().removeClass(this.disabledClass);
21004                 e.dom.disabled = false;
21005             });
21006         }
21007         
21008         this.disabled = false;
21009         this.fireEvent("enable", this);
21010         return this;
21011     },
21012     
21013     setBoxLabel : function(v)
21014     {
21015         this.boxLabel = v;
21016         
21017         if(this.rendered){
21018             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21019         }
21020     }
21021
21022 });
21023
21024 Roo.apply(Roo.bootstrap.CheckBox, {
21025     
21026     groups: {},
21027     
21028      /**
21029     * register a CheckBox Group
21030     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21031     */
21032     register : function(checkbox)
21033     {
21034         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21035             this.groups[checkbox.groupId] = {};
21036         }
21037         
21038         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21039             return;
21040         }
21041         
21042         this.groups[checkbox.groupId][checkbox.name] = checkbox;
21043         
21044     },
21045     /**
21046     * fetch a CheckBox Group based on the group ID
21047     * @param {string} the group ID
21048     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21049     */
21050     get: function(groupId) {
21051         if (typeof(this.groups[groupId]) == 'undefined') {
21052             return false;
21053         }
21054         
21055         return this.groups[groupId] ;
21056     }
21057     
21058     
21059 });
21060 /*
21061  * - LGPL
21062  *
21063  * RadioItem
21064  * 
21065  */
21066
21067 /**
21068  * @class Roo.bootstrap.Radio
21069  * @extends Roo.bootstrap.Component
21070  * Bootstrap Radio class
21071  * @cfg {String} boxLabel - the label associated
21072  * @cfg {String} value - the value of radio
21073  * 
21074  * @constructor
21075  * Create a new Radio
21076  * @param {Object} config The config object
21077  */
21078 Roo.bootstrap.Radio = function(config){
21079     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21080     
21081 };
21082
21083 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21084     
21085     boxLabel : '',
21086     
21087     value : '',
21088     
21089     getAutoCreate : function()
21090     {
21091         var cfg = {
21092             tag : 'div',
21093             cls : 'form-group radio',
21094             cn : [
21095                 {
21096                     tag : 'label',
21097                     cls : 'box-label',
21098                     html : this.boxLabel
21099                 }
21100             ]
21101         };
21102         
21103         return cfg;
21104     },
21105     
21106     initEvents : function() 
21107     {
21108         this.parent().register(this);
21109         
21110         this.el.on('click', this.onClick, this);
21111         
21112     },
21113     
21114     onClick : function(e)
21115     {
21116         if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21117             this.setChecked(true);
21118         }
21119     },
21120     
21121     setChecked : function(state, suppressEvent)
21122     {
21123         this.parent().setValue(this.value, suppressEvent);
21124         
21125     },
21126     
21127     setBoxLabel : function(v)
21128     {
21129         this.boxLabel = v;
21130         
21131         if(this.rendered){
21132             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21133         }
21134     }
21135     
21136 });
21137  
21138
21139  /*
21140  * - LGPL
21141  *
21142  * Input
21143  * 
21144  */
21145
21146 /**
21147  * @class Roo.bootstrap.SecurePass
21148  * @extends Roo.bootstrap.Input
21149  * Bootstrap SecurePass class
21150  *
21151  * 
21152  * @constructor
21153  * Create a new SecurePass
21154  * @param {Object} config The config object
21155  */
21156  
21157 Roo.bootstrap.SecurePass = function (config) {
21158     // these go here, so the translation tool can replace them..
21159     this.errors = {
21160         PwdEmpty: "Please type a password, and then retype it to confirm.",
21161         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21162         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21163         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21164         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21165         FNInPwd: "Your password can't contain your first name. Please type a different password.",
21166         LNInPwd: "Your password can't contain your last name. Please type a different password.",
21167         TooWeak: "Your password is Too Weak."
21168     },
21169     this.meterLabel = "Password strength:";
21170     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21171     this.meterClass = [
21172         "roo-password-meter-tooweak", 
21173         "roo-password-meter-weak", 
21174         "roo-password-meter-medium", 
21175         "roo-password-meter-strong", 
21176         "roo-password-meter-grey"
21177     ];
21178     
21179     this.errors = {};
21180     
21181     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21182 }
21183
21184 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21185     /**
21186      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21187      * {
21188      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
21189      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21190      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21191      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21192      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21193      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
21194      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
21195      * })
21196      */
21197     // private
21198     
21199     meterWidth: 300,
21200     errorMsg :'',    
21201     errors: false,
21202     imageRoot: '/',
21203     /**
21204      * @cfg {String/Object} Label for the strength meter (defaults to
21205      * 'Password strength:')
21206      */
21207     // private
21208     meterLabel: '',
21209     /**
21210      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21211      * ['Weak', 'Medium', 'Strong'])
21212      */
21213     // private    
21214     pwdStrengths: false,    
21215     // private
21216     strength: 0,
21217     // private
21218     _lastPwd: null,
21219     // private
21220     kCapitalLetter: 0,
21221     kSmallLetter: 1,
21222     kDigit: 2,
21223     kPunctuation: 3,
21224     
21225     insecure: false,
21226     // private
21227     initEvents: function ()
21228     {
21229         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21230
21231         if (this.el.is('input[type=password]') && Roo.isSafari) {
21232             this.el.on('keydown', this.SafariOnKeyDown, this);
21233         }
21234
21235         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21236     },
21237     // private
21238     onRender: function (ct, position)
21239     {
21240         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21241         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21242         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21243
21244         this.trigger.createChild({
21245                    cn: [
21246                     {
21247                     //id: 'PwdMeter',
21248                     tag: 'div',
21249                     cls: 'roo-password-meter-grey col-xs-12',
21250                     style: {
21251                         //width: 0,
21252                         //width: this.meterWidth + 'px'                                                
21253                         }
21254                     },
21255                     {                            
21256                          cls: 'roo-password-meter-text'                          
21257                     }
21258                 ]            
21259         });
21260
21261          
21262         if (this.hideTrigger) {
21263             this.trigger.setDisplayed(false);
21264         }
21265         this.setSize(this.width || '', this.height || '');
21266     },
21267     // private
21268     onDestroy: function ()
21269     {
21270         if (this.trigger) {
21271             this.trigger.removeAllListeners();
21272             this.trigger.remove();
21273         }
21274         if (this.wrap) {
21275             this.wrap.remove();
21276         }
21277         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21278     },
21279     // private
21280     checkStrength: function ()
21281     {
21282         var pwd = this.inputEl().getValue();
21283         if (pwd == this._lastPwd) {
21284             return;
21285         }
21286
21287         var strength;
21288         if (this.ClientSideStrongPassword(pwd)) {
21289             strength = 3;
21290         } else if (this.ClientSideMediumPassword(pwd)) {
21291             strength = 2;
21292         } else if (this.ClientSideWeakPassword(pwd)) {
21293             strength = 1;
21294         } else {
21295             strength = 0;
21296         }
21297         
21298         Roo.log('strength1: ' + strength);
21299         
21300         //var pm = this.trigger.child('div/div/div').dom;
21301         var pm = this.trigger.child('div/div');
21302         pm.removeClass(this.meterClass);
21303         pm.addClass(this.meterClass[strength]);
21304                 
21305         
21306         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21307                 
21308         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21309         
21310         this._lastPwd = pwd;
21311     },
21312     reset: function ()
21313     {
21314         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21315         
21316         this._lastPwd = '';
21317         
21318         var pm = this.trigger.child('div/div');
21319         pm.removeClass(this.meterClass);
21320         pm.addClass('roo-password-meter-grey');        
21321         
21322         
21323         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21324         
21325         pt.innerHTML = '';
21326         this.inputEl().dom.type='password';
21327     },
21328     // private
21329     validateValue: function (value)
21330     {
21331         
21332         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21333             return false;
21334         }
21335         if (value.length == 0) {
21336             if (this.allowBlank) {
21337                 this.clearInvalid();
21338                 return true;
21339             }
21340
21341             this.markInvalid(this.errors.PwdEmpty);
21342             this.errorMsg = this.errors.PwdEmpty;
21343             return false;
21344         }
21345         
21346         if(this.insecure){
21347             return true;
21348         }
21349         
21350         if ('[\x21-\x7e]*'.match(value)) {
21351             this.markInvalid(this.errors.PwdBadChar);
21352             this.errorMsg = this.errors.PwdBadChar;
21353             return false;
21354         }
21355         if (value.length < 6) {
21356             this.markInvalid(this.errors.PwdShort);
21357             this.errorMsg = this.errors.PwdShort;
21358             return false;
21359         }
21360         if (value.length > 16) {
21361             this.markInvalid(this.errors.PwdLong);
21362             this.errorMsg = this.errors.PwdLong;
21363             return false;
21364         }
21365         var strength;
21366         if (this.ClientSideStrongPassword(value)) {
21367             strength = 3;
21368         } else if (this.ClientSideMediumPassword(value)) {
21369             strength = 2;
21370         } else if (this.ClientSideWeakPassword(value)) {
21371             strength = 1;
21372         } else {
21373             strength = 0;
21374         }
21375
21376         
21377         if (strength < 2) {
21378             //this.markInvalid(this.errors.TooWeak);
21379             this.errorMsg = this.errors.TooWeak;
21380             //return false;
21381         }
21382         
21383         
21384         console.log('strength2: ' + strength);
21385         
21386         //var pm = this.trigger.child('div/div/div').dom;
21387         
21388         var pm = this.trigger.child('div/div');
21389         pm.removeClass(this.meterClass);
21390         pm.addClass(this.meterClass[strength]);
21391                 
21392         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21393                 
21394         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21395         
21396         this.errorMsg = ''; 
21397         return true;
21398     },
21399     // private
21400     CharacterSetChecks: function (type)
21401     {
21402         this.type = type;
21403         this.fResult = false;
21404     },
21405     // private
21406     isctype: function (character, type)
21407     {
21408         switch (type) {  
21409             case this.kCapitalLetter:
21410                 if (character >= 'A' && character <= 'Z') {
21411                     return true;
21412                 }
21413                 break;
21414             
21415             case this.kSmallLetter:
21416                 if (character >= 'a' && character <= 'z') {
21417                     return true;
21418                 }
21419                 break;
21420             
21421             case this.kDigit:
21422                 if (character >= '0' && character <= '9') {
21423                     return true;
21424                 }
21425                 break;
21426             
21427             case this.kPunctuation:
21428                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21429                     return true;
21430                 }
21431                 break;
21432             
21433             default:
21434                 return false;
21435         }
21436
21437     },
21438     // private
21439     IsLongEnough: function (pwd, size)
21440     {
21441         return !(pwd == null || isNaN(size) || pwd.length < size);
21442     },
21443     // private
21444     SpansEnoughCharacterSets: function (word, nb)
21445     {
21446         if (!this.IsLongEnough(word, nb))
21447         {
21448             return false;
21449         }
21450
21451         var characterSetChecks = new Array(
21452             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21453             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21454         );
21455         
21456         for (var index = 0; index < word.length; ++index) {
21457             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21458                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21459                     characterSetChecks[nCharSet].fResult = true;
21460                     break;
21461                 }
21462             }
21463         }
21464
21465         var nCharSets = 0;
21466         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21467             if (characterSetChecks[nCharSet].fResult) {
21468                 ++nCharSets;
21469             }
21470         }
21471
21472         if (nCharSets < nb) {
21473             return false;
21474         }
21475         return true;
21476     },
21477     // private
21478     ClientSideStrongPassword: function (pwd)
21479     {
21480         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21481     },
21482     // private
21483     ClientSideMediumPassword: function (pwd)
21484     {
21485         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21486     },
21487     // private
21488     ClientSideWeakPassword: function (pwd)
21489     {
21490         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21491     }
21492           
21493 })//<script type="text/javascript">
21494
21495 /*
21496  * Based  Ext JS Library 1.1.1
21497  * Copyright(c) 2006-2007, Ext JS, LLC.
21498  * LGPL
21499  *
21500  */
21501  
21502 /**
21503  * @class Roo.HtmlEditorCore
21504  * @extends Roo.Component
21505  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21506  *
21507  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21508  */
21509
21510 Roo.HtmlEditorCore = function(config){
21511     
21512     
21513     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21514     
21515     
21516     this.addEvents({
21517         /**
21518          * @event initialize
21519          * Fires when the editor is fully initialized (including the iframe)
21520          * @param {Roo.HtmlEditorCore} this
21521          */
21522         initialize: true,
21523         /**
21524          * @event activate
21525          * Fires when the editor is first receives the focus. Any insertion must wait
21526          * until after this event.
21527          * @param {Roo.HtmlEditorCore} this
21528          */
21529         activate: true,
21530          /**
21531          * @event beforesync
21532          * Fires before the textarea is updated with content from the editor iframe. Return false
21533          * to cancel the sync.
21534          * @param {Roo.HtmlEditorCore} this
21535          * @param {String} html
21536          */
21537         beforesync: true,
21538          /**
21539          * @event beforepush
21540          * Fires before the iframe editor is updated with content from the textarea. Return false
21541          * to cancel the push.
21542          * @param {Roo.HtmlEditorCore} this
21543          * @param {String} html
21544          */
21545         beforepush: true,
21546          /**
21547          * @event sync
21548          * Fires when the textarea is updated with content from the editor iframe.
21549          * @param {Roo.HtmlEditorCore} this
21550          * @param {String} html
21551          */
21552         sync: true,
21553          /**
21554          * @event push
21555          * Fires when the iframe editor is updated with content from the textarea.
21556          * @param {Roo.HtmlEditorCore} this
21557          * @param {String} html
21558          */
21559         push: true,
21560         
21561         /**
21562          * @event editorevent
21563          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21564          * @param {Roo.HtmlEditorCore} this
21565          */
21566         editorevent: true
21567         
21568     });
21569     
21570     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21571     
21572     // defaults : white / black...
21573     this.applyBlacklists();
21574     
21575     
21576     
21577 };
21578
21579
21580 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21581
21582
21583      /**
21584      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21585      */
21586     
21587     owner : false,
21588     
21589      /**
21590      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21591      *                        Roo.resizable.
21592      */
21593     resizable : false,
21594      /**
21595      * @cfg {Number} height (in pixels)
21596      */   
21597     height: 300,
21598    /**
21599      * @cfg {Number} width (in pixels)
21600      */   
21601     width: 500,
21602     
21603     /**
21604      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21605      * 
21606      */
21607     stylesheets: false,
21608     
21609     // id of frame..
21610     frameId: false,
21611     
21612     // private properties
21613     validationEvent : false,
21614     deferHeight: true,
21615     initialized : false,
21616     activated : false,
21617     sourceEditMode : false,
21618     onFocus : Roo.emptyFn,
21619     iframePad:3,
21620     hideMode:'offsets',
21621     
21622     clearUp: true,
21623     
21624     // blacklist + whitelisted elements..
21625     black: false,
21626     white: false,
21627      
21628     bodyCls : '',
21629
21630     /**
21631      * Protected method that will not generally be called directly. It
21632      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21633      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21634      */
21635     getDocMarkup : function(){
21636         // body styles..
21637         var st = '';
21638         
21639         // inherit styels from page...?? 
21640         if (this.stylesheets === false) {
21641             
21642             Roo.get(document.head).select('style').each(function(node) {
21643                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21644             });
21645             
21646             Roo.get(document.head).select('link').each(function(node) { 
21647                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21648             });
21649             
21650         } else if (!this.stylesheets.length) {
21651                 // simple..
21652                 st = '<style type="text/css">' +
21653                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21654                    '</style>';
21655         } else { 
21656             st = '<style type="text/css">' +
21657                     this.stylesheets +
21658                 '</style>';
21659         }
21660         
21661         st +=  '<style type="text/css">' +
21662             'IMG { cursor: pointer } ' +
21663         '</style>';
21664
21665         var cls = 'roo-htmleditor-body';
21666         
21667         if(this.bodyCls.length){
21668             cls += ' ' + this.bodyCls;
21669         }
21670         
21671         return '<html><head>' + st  +
21672             //<style type="text/css">' +
21673             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21674             //'</style>' +
21675             ' </head><body class="' +  cls + '"></body></html>';
21676     },
21677
21678     // private
21679     onRender : function(ct, position)
21680     {
21681         var _t = this;
21682         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21683         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21684         
21685         
21686         this.el.dom.style.border = '0 none';
21687         this.el.dom.setAttribute('tabIndex', -1);
21688         this.el.addClass('x-hidden hide');
21689         
21690         
21691         
21692         if(Roo.isIE){ // fix IE 1px bogus margin
21693             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21694         }
21695        
21696         
21697         this.frameId = Roo.id();
21698         
21699          
21700         
21701         var iframe = this.owner.wrap.createChild({
21702             tag: 'iframe',
21703             cls: 'form-control', // bootstrap..
21704             id: this.frameId,
21705             name: this.frameId,
21706             frameBorder : 'no',
21707             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21708         }, this.el
21709         );
21710         
21711         
21712         this.iframe = iframe.dom;
21713
21714          this.assignDocWin();
21715         
21716         this.doc.designMode = 'on';
21717        
21718         this.doc.open();
21719         this.doc.write(this.getDocMarkup());
21720         this.doc.close();
21721
21722         
21723         var task = { // must defer to wait for browser to be ready
21724             run : function(){
21725                 //console.log("run task?" + this.doc.readyState);
21726                 this.assignDocWin();
21727                 if(this.doc.body || this.doc.readyState == 'complete'){
21728                     try {
21729                         this.doc.designMode="on";
21730                     } catch (e) {
21731                         return;
21732                     }
21733                     Roo.TaskMgr.stop(task);
21734                     this.initEditor.defer(10, this);
21735                 }
21736             },
21737             interval : 10,
21738             duration: 10000,
21739             scope: this
21740         };
21741         Roo.TaskMgr.start(task);
21742
21743     },
21744
21745     // private
21746     onResize : function(w, h)
21747     {
21748          Roo.log('resize: ' +w + ',' + h );
21749         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21750         if(!this.iframe){
21751             return;
21752         }
21753         if(typeof w == 'number'){
21754             
21755             this.iframe.style.width = w + 'px';
21756         }
21757         if(typeof h == 'number'){
21758             
21759             this.iframe.style.height = h + 'px';
21760             if(this.doc){
21761                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21762             }
21763         }
21764         
21765     },
21766
21767     /**
21768      * Toggles the editor between standard and source edit mode.
21769      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21770      */
21771     toggleSourceEdit : function(sourceEditMode){
21772         
21773         this.sourceEditMode = sourceEditMode === true;
21774         
21775         if(this.sourceEditMode){
21776  
21777             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21778             
21779         }else{
21780             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21781             //this.iframe.className = '';
21782             this.deferFocus();
21783         }
21784         //this.setSize(this.owner.wrap.getSize());
21785         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21786     },
21787
21788     
21789   
21790
21791     /**
21792      * Protected method that will not generally be called directly. If you need/want
21793      * custom HTML cleanup, this is the method you should override.
21794      * @param {String} html The HTML to be cleaned
21795      * return {String} The cleaned HTML
21796      */
21797     cleanHtml : function(html){
21798         html = String(html);
21799         if(html.length > 5){
21800             if(Roo.isSafari){ // strip safari nonsense
21801                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21802             }
21803         }
21804         if(html == '&nbsp;'){
21805             html = '';
21806         }
21807         return html;
21808     },
21809
21810     /**
21811      * HTML Editor -> Textarea
21812      * Protected method that will not generally be called directly. Syncs the contents
21813      * of the editor iframe with the textarea.
21814      */
21815     syncValue : function(){
21816         if(this.initialized){
21817             var bd = (this.doc.body || this.doc.documentElement);
21818             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21819             var html = bd.innerHTML;
21820             if(Roo.isSafari){
21821                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21822                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21823                 if(m && m[1]){
21824                     html = '<div style="'+m[0]+'">' + html + '</div>';
21825                 }
21826             }
21827             html = this.cleanHtml(html);
21828             // fix up the special chars.. normaly like back quotes in word...
21829             // however we do not want to do this with chinese..
21830             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21831                 var cc = b.charCodeAt();
21832                 if (
21833                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21834                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21835                     (cc >= 0xf900 && cc < 0xfb00 )
21836                 ) {
21837                         return b;
21838                 }
21839                 return "&#"+cc+";" 
21840             });
21841             if(this.owner.fireEvent('beforesync', this, html) !== false){
21842                 this.el.dom.value = html;
21843                 this.owner.fireEvent('sync', this, html);
21844             }
21845         }
21846     },
21847
21848     /**
21849      * Protected method that will not generally be called directly. Pushes the value of the textarea
21850      * into the iframe editor.
21851      */
21852     pushValue : function(){
21853         if(this.initialized){
21854             var v = this.el.dom.value.trim();
21855             
21856 //            if(v.length < 1){
21857 //                v = '&#160;';
21858 //            }
21859             
21860             if(this.owner.fireEvent('beforepush', this, v) !== false){
21861                 var d = (this.doc.body || this.doc.documentElement);
21862                 d.innerHTML = v;
21863                 this.cleanUpPaste();
21864                 this.el.dom.value = d.innerHTML;
21865                 this.owner.fireEvent('push', this, v);
21866             }
21867         }
21868     },
21869
21870     // private
21871     deferFocus : function(){
21872         this.focus.defer(10, this);
21873     },
21874
21875     // doc'ed in Field
21876     focus : function(){
21877         if(this.win && !this.sourceEditMode){
21878             this.win.focus();
21879         }else{
21880             this.el.focus();
21881         }
21882     },
21883     
21884     assignDocWin: function()
21885     {
21886         var iframe = this.iframe;
21887         
21888          if(Roo.isIE){
21889             this.doc = iframe.contentWindow.document;
21890             this.win = iframe.contentWindow;
21891         } else {
21892 //            if (!Roo.get(this.frameId)) {
21893 //                return;
21894 //            }
21895 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21896 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21897             
21898             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21899                 return;
21900             }
21901             
21902             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21903             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21904         }
21905     },
21906     
21907     // private
21908     initEditor : function(){
21909         //console.log("INIT EDITOR");
21910         this.assignDocWin();
21911         
21912         
21913         
21914         this.doc.designMode="on";
21915         this.doc.open();
21916         this.doc.write(this.getDocMarkup());
21917         this.doc.close();
21918         
21919         var dbody = (this.doc.body || this.doc.documentElement);
21920         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21921         // this copies styles from the containing element into thsi one..
21922         // not sure why we need all of this..
21923         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21924         
21925         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21926         //ss['background-attachment'] = 'fixed'; // w3c
21927         dbody.bgProperties = 'fixed'; // ie
21928         //Roo.DomHelper.applyStyles(dbody, ss);
21929         Roo.EventManager.on(this.doc, {
21930             //'mousedown': this.onEditorEvent,
21931             'mouseup': this.onEditorEvent,
21932             'dblclick': this.onEditorEvent,
21933             'click': this.onEditorEvent,
21934             'keyup': this.onEditorEvent,
21935             buffer:100,
21936             scope: this
21937         });
21938         if(Roo.isGecko){
21939             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21940         }
21941         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21942             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21943         }
21944         this.initialized = true;
21945
21946         this.owner.fireEvent('initialize', this);
21947         this.pushValue();
21948     },
21949
21950     // private
21951     onDestroy : function(){
21952         
21953         
21954         
21955         if(this.rendered){
21956             
21957             //for (var i =0; i < this.toolbars.length;i++) {
21958             //    // fixme - ask toolbars for heights?
21959             //    this.toolbars[i].onDestroy();
21960            // }
21961             
21962             //this.wrap.dom.innerHTML = '';
21963             //this.wrap.remove();
21964         }
21965     },
21966
21967     // private
21968     onFirstFocus : function(){
21969         
21970         this.assignDocWin();
21971         
21972         
21973         this.activated = true;
21974          
21975     
21976         if(Roo.isGecko){ // prevent silly gecko errors
21977             this.win.focus();
21978             var s = this.win.getSelection();
21979             if(!s.focusNode || s.focusNode.nodeType != 3){
21980                 var r = s.getRangeAt(0);
21981                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21982                 r.collapse(true);
21983                 this.deferFocus();
21984             }
21985             try{
21986                 this.execCmd('useCSS', true);
21987                 this.execCmd('styleWithCSS', false);
21988             }catch(e){}
21989         }
21990         this.owner.fireEvent('activate', this);
21991     },
21992
21993     // private
21994     adjustFont: function(btn){
21995         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21996         //if(Roo.isSafari){ // safari
21997         //    adjust *= 2;
21998        // }
21999         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22000         if(Roo.isSafari){ // safari
22001             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22002             v =  (v < 10) ? 10 : v;
22003             v =  (v > 48) ? 48 : v;
22004             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22005             
22006         }
22007         
22008         
22009         v = Math.max(1, v+adjust);
22010         
22011         this.execCmd('FontSize', v  );
22012     },
22013
22014     onEditorEvent : function(e)
22015     {
22016         this.owner.fireEvent('editorevent', this, e);
22017       //  this.updateToolbar();
22018         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22019     },
22020
22021     insertTag : function(tg)
22022     {
22023         // could be a bit smarter... -> wrap the current selected tRoo..
22024         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22025             
22026             range = this.createRange(this.getSelection());
22027             var wrappingNode = this.doc.createElement(tg.toLowerCase());
22028             wrappingNode.appendChild(range.extractContents());
22029             range.insertNode(wrappingNode);
22030
22031             return;
22032             
22033             
22034             
22035         }
22036         this.execCmd("formatblock",   tg);
22037         
22038     },
22039     
22040     insertText : function(txt)
22041     {
22042         
22043         
22044         var range = this.createRange();
22045         range.deleteContents();
22046                //alert(Sender.getAttribute('label'));
22047                
22048         range.insertNode(this.doc.createTextNode(txt));
22049     } ,
22050     
22051      
22052
22053     /**
22054      * Executes a Midas editor command on the editor document and performs necessary focus and
22055      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22056      * @param {String} cmd The Midas command
22057      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22058      */
22059     relayCmd : function(cmd, value){
22060         this.win.focus();
22061         this.execCmd(cmd, value);
22062         this.owner.fireEvent('editorevent', this);
22063         //this.updateToolbar();
22064         this.owner.deferFocus();
22065     },
22066
22067     /**
22068      * Executes a Midas editor command directly on the editor document.
22069      * For visual commands, you should use {@link #relayCmd} instead.
22070      * <b>This should only be called after the editor is initialized.</b>
22071      * @param {String} cmd The Midas command
22072      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22073      */
22074     execCmd : function(cmd, value){
22075         this.doc.execCommand(cmd, false, value === undefined ? null : value);
22076         this.syncValue();
22077     },
22078  
22079  
22080    
22081     /**
22082      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22083      * to insert tRoo.
22084      * @param {String} text | dom node.. 
22085      */
22086     insertAtCursor : function(text)
22087     {
22088         
22089         if(!this.activated){
22090             return;
22091         }
22092         /*
22093         if(Roo.isIE){
22094             this.win.focus();
22095             var r = this.doc.selection.createRange();
22096             if(r){
22097                 r.collapse(true);
22098                 r.pasteHTML(text);
22099                 this.syncValue();
22100                 this.deferFocus();
22101             
22102             }
22103             return;
22104         }
22105         */
22106         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22107             this.win.focus();
22108             
22109             
22110             // from jquery ui (MIT licenced)
22111             var range, node;
22112             var win = this.win;
22113             
22114             if (win.getSelection && win.getSelection().getRangeAt) {
22115                 range = win.getSelection().getRangeAt(0);
22116                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22117                 range.insertNode(node);
22118             } else if (win.document.selection && win.document.selection.createRange) {
22119                 // no firefox support
22120                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22121                 win.document.selection.createRange().pasteHTML(txt);
22122             } else {
22123                 // no firefox support
22124                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22125                 this.execCmd('InsertHTML', txt);
22126             } 
22127             
22128             this.syncValue();
22129             
22130             this.deferFocus();
22131         }
22132     },
22133  // private
22134     mozKeyPress : function(e){
22135         if(e.ctrlKey){
22136             var c = e.getCharCode(), cmd;
22137           
22138             if(c > 0){
22139                 c = String.fromCharCode(c).toLowerCase();
22140                 switch(c){
22141                     case 'b':
22142                         cmd = 'bold';
22143                         break;
22144                     case 'i':
22145                         cmd = 'italic';
22146                         break;
22147                     
22148                     case 'u':
22149                         cmd = 'underline';
22150                         break;
22151                     
22152                     case 'v':
22153                         this.cleanUpPaste.defer(100, this);
22154                         return;
22155                         
22156                 }
22157                 if(cmd){
22158                     this.win.focus();
22159                     this.execCmd(cmd);
22160                     this.deferFocus();
22161                     e.preventDefault();
22162                 }
22163                 
22164             }
22165         }
22166     },
22167
22168     // private
22169     fixKeys : function(){ // load time branching for fastest keydown performance
22170         if(Roo.isIE){
22171             return function(e){
22172                 var k = e.getKey(), r;
22173                 if(k == e.TAB){
22174                     e.stopEvent();
22175                     r = this.doc.selection.createRange();
22176                     if(r){
22177                         r.collapse(true);
22178                         r.pasteHTML('&#160;&#160;&#160;&#160;');
22179                         this.deferFocus();
22180                     }
22181                     return;
22182                 }
22183                 
22184                 if(k == e.ENTER){
22185                     r = this.doc.selection.createRange();
22186                     if(r){
22187                         var target = r.parentElement();
22188                         if(!target || target.tagName.toLowerCase() != 'li'){
22189                             e.stopEvent();
22190                             r.pasteHTML('<br />');
22191                             r.collapse(false);
22192                             r.select();
22193                         }
22194                     }
22195                 }
22196                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22197                     this.cleanUpPaste.defer(100, this);
22198                     return;
22199                 }
22200                 
22201                 
22202             };
22203         }else if(Roo.isOpera){
22204             return function(e){
22205                 var k = e.getKey();
22206                 if(k == e.TAB){
22207                     e.stopEvent();
22208                     this.win.focus();
22209                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
22210                     this.deferFocus();
22211                 }
22212                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22213                     this.cleanUpPaste.defer(100, this);
22214                     return;
22215                 }
22216                 
22217             };
22218         }else if(Roo.isSafari){
22219             return function(e){
22220                 var k = e.getKey();
22221                 
22222                 if(k == e.TAB){
22223                     e.stopEvent();
22224                     this.execCmd('InsertText','\t');
22225                     this.deferFocus();
22226                     return;
22227                 }
22228                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22229                     this.cleanUpPaste.defer(100, this);
22230                     return;
22231                 }
22232                 
22233              };
22234         }
22235     }(),
22236     
22237     getAllAncestors: function()
22238     {
22239         var p = this.getSelectedNode();
22240         var a = [];
22241         if (!p) {
22242             a.push(p); // push blank onto stack..
22243             p = this.getParentElement();
22244         }
22245         
22246         
22247         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22248             a.push(p);
22249             p = p.parentNode;
22250         }
22251         a.push(this.doc.body);
22252         return a;
22253     },
22254     lastSel : false,
22255     lastSelNode : false,
22256     
22257     
22258     getSelection : function() 
22259     {
22260         this.assignDocWin();
22261         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22262     },
22263     
22264     getSelectedNode: function() 
22265     {
22266         // this may only work on Gecko!!!
22267         
22268         // should we cache this!!!!
22269         
22270         
22271         
22272          
22273         var range = this.createRange(this.getSelection()).cloneRange();
22274         
22275         if (Roo.isIE) {
22276             var parent = range.parentElement();
22277             while (true) {
22278                 var testRange = range.duplicate();
22279                 testRange.moveToElementText(parent);
22280                 if (testRange.inRange(range)) {
22281                     break;
22282                 }
22283                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22284                     break;
22285                 }
22286                 parent = parent.parentElement;
22287             }
22288             return parent;
22289         }
22290         
22291         // is ancestor a text element.
22292         var ac =  range.commonAncestorContainer;
22293         if (ac.nodeType == 3) {
22294             ac = ac.parentNode;
22295         }
22296         
22297         var ar = ac.childNodes;
22298          
22299         var nodes = [];
22300         var other_nodes = [];
22301         var has_other_nodes = false;
22302         for (var i=0;i<ar.length;i++) {
22303             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22304                 continue;
22305             }
22306             // fullly contained node.
22307             
22308             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22309                 nodes.push(ar[i]);
22310                 continue;
22311             }
22312             
22313             // probably selected..
22314             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22315                 other_nodes.push(ar[i]);
22316                 continue;
22317             }
22318             // outer..
22319             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22320                 continue;
22321             }
22322             
22323             
22324             has_other_nodes = true;
22325         }
22326         if (!nodes.length && other_nodes.length) {
22327             nodes= other_nodes;
22328         }
22329         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22330             return false;
22331         }
22332         
22333         return nodes[0];
22334     },
22335     createRange: function(sel)
22336     {
22337         // this has strange effects when using with 
22338         // top toolbar - not sure if it's a great idea.
22339         //this.editor.contentWindow.focus();
22340         if (typeof sel != "undefined") {
22341             try {
22342                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22343             } catch(e) {
22344                 return this.doc.createRange();
22345             }
22346         } else {
22347             return this.doc.createRange();
22348         }
22349     },
22350     getParentElement: function()
22351     {
22352         
22353         this.assignDocWin();
22354         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22355         
22356         var range = this.createRange(sel);
22357          
22358         try {
22359             var p = range.commonAncestorContainer;
22360             while (p.nodeType == 3) { // text node
22361                 p = p.parentNode;
22362             }
22363             return p;
22364         } catch (e) {
22365             return null;
22366         }
22367     
22368     },
22369     /***
22370      *
22371      * Range intersection.. the hard stuff...
22372      *  '-1' = before
22373      *  '0' = hits..
22374      *  '1' = after.
22375      *         [ -- selected range --- ]
22376      *   [fail]                        [fail]
22377      *
22378      *    basically..
22379      *      if end is before start or  hits it. fail.
22380      *      if start is after end or hits it fail.
22381      *
22382      *   if either hits (but other is outside. - then it's not 
22383      *   
22384      *    
22385      **/
22386     
22387     
22388     // @see http://www.thismuchiknow.co.uk/?p=64.
22389     rangeIntersectsNode : function(range, node)
22390     {
22391         var nodeRange = node.ownerDocument.createRange();
22392         try {
22393             nodeRange.selectNode(node);
22394         } catch (e) {
22395             nodeRange.selectNodeContents(node);
22396         }
22397     
22398         var rangeStartRange = range.cloneRange();
22399         rangeStartRange.collapse(true);
22400     
22401         var rangeEndRange = range.cloneRange();
22402         rangeEndRange.collapse(false);
22403     
22404         var nodeStartRange = nodeRange.cloneRange();
22405         nodeStartRange.collapse(true);
22406     
22407         var nodeEndRange = nodeRange.cloneRange();
22408         nodeEndRange.collapse(false);
22409     
22410         return rangeStartRange.compareBoundaryPoints(
22411                  Range.START_TO_START, nodeEndRange) == -1 &&
22412                rangeEndRange.compareBoundaryPoints(
22413                  Range.START_TO_START, nodeStartRange) == 1;
22414         
22415          
22416     },
22417     rangeCompareNode : function(range, node)
22418     {
22419         var nodeRange = node.ownerDocument.createRange();
22420         try {
22421             nodeRange.selectNode(node);
22422         } catch (e) {
22423             nodeRange.selectNodeContents(node);
22424         }
22425         
22426         
22427         range.collapse(true);
22428     
22429         nodeRange.collapse(true);
22430      
22431         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22432         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22433          
22434         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22435         
22436         var nodeIsBefore   =  ss == 1;
22437         var nodeIsAfter    = ee == -1;
22438         
22439         if (nodeIsBefore && nodeIsAfter) {
22440             return 0; // outer
22441         }
22442         if (!nodeIsBefore && nodeIsAfter) {
22443             return 1; //right trailed.
22444         }
22445         
22446         if (nodeIsBefore && !nodeIsAfter) {
22447             return 2;  // left trailed.
22448         }
22449         // fully contined.
22450         return 3;
22451     },
22452
22453     // private? - in a new class?
22454     cleanUpPaste :  function()
22455     {
22456         // cleans up the whole document..
22457         Roo.log('cleanuppaste');
22458         
22459         this.cleanUpChildren(this.doc.body);
22460         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22461         if (clean != this.doc.body.innerHTML) {
22462             this.doc.body.innerHTML = clean;
22463         }
22464         
22465     },
22466     
22467     cleanWordChars : function(input) {// change the chars to hex code
22468         var he = Roo.HtmlEditorCore;
22469         
22470         var output = input;
22471         Roo.each(he.swapCodes, function(sw) { 
22472             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22473             
22474             output = output.replace(swapper, sw[1]);
22475         });
22476         
22477         return output;
22478     },
22479     
22480     
22481     cleanUpChildren : function (n)
22482     {
22483         if (!n.childNodes.length) {
22484             return;
22485         }
22486         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22487            this.cleanUpChild(n.childNodes[i]);
22488         }
22489     },
22490     
22491     
22492         
22493     
22494     cleanUpChild : function (node)
22495     {
22496         var ed = this;
22497         //console.log(node);
22498         if (node.nodeName == "#text") {
22499             // clean up silly Windows -- stuff?
22500             return; 
22501         }
22502         if (node.nodeName == "#comment") {
22503             node.parentNode.removeChild(node);
22504             // clean up silly Windows -- stuff?
22505             return; 
22506         }
22507         var lcname = node.tagName.toLowerCase();
22508         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22509         // whitelist of tags..
22510         
22511         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22512             // remove node.
22513             node.parentNode.removeChild(node);
22514             return;
22515             
22516         }
22517         
22518         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22519         
22520         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22521         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22522         
22523         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22524         //    remove_keep_children = true;
22525         //}
22526         
22527         if (remove_keep_children) {
22528             this.cleanUpChildren(node);
22529             // inserts everything just before this node...
22530             while (node.childNodes.length) {
22531                 var cn = node.childNodes[0];
22532                 node.removeChild(cn);
22533                 node.parentNode.insertBefore(cn, node);
22534             }
22535             node.parentNode.removeChild(node);
22536             return;
22537         }
22538         
22539         if (!node.attributes || !node.attributes.length) {
22540             this.cleanUpChildren(node);
22541             return;
22542         }
22543         
22544         function cleanAttr(n,v)
22545         {
22546             
22547             if (v.match(/^\./) || v.match(/^\//)) {
22548                 return;
22549             }
22550             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22551                 return;
22552             }
22553             if (v.match(/^#/)) {
22554                 return;
22555             }
22556 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22557             node.removeAttribute(n);
22558             
22559         }
22560         
22561         var cwhite = this.cwhite;
22562         var cblack = this.cblack;
22563             
22564         function cleanStyle(n,v)
22565         {
22566             if (v.match(/expression/)) { //XSS?? should we even bother..
22567                 node.removeAttribute(n);
22568                 return;
22569             }
22570             
22571             var parts = v.split(/;/);
22572             var clean = [];
22573             
22574             Roo.each(parts, function(p) {
22575                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22576                 if (!p.length) {
22577                     return true;
22578                 }
22579                 var l = p.split(':').shift().replace(/\s+/g,'');
22580                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22581                 
22582                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22583 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22584                     //node.removeAttribute(n);
22585                     return true;
22586                 }
22587                 //Roo.log()
22588                 // only allow 'c whitelisted system attributes'
22589                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22590 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22591                     //node.removeAttribute(n);
22592                     return true;
22593                 }
22594                 
22595                 
22596                  
22597                 
22598                 clean.push(p);
22599                 return true;
22600             });
22601             if (clean.length) { 
22602                 node.setAttribute(n, clean.join(';'));
22603             } else {
22604                 node.removeAttribute(n);
22605             }
22606             
22607         }
22608         
22609         
22610         for (var i = node.attributes.length-1; i > -1 ; i--) {
22611             var a = node.attributes[i];
22612             //console.log(a);
22613             
22614             if (a.name.toLowerCase().substr(0,2)=='on')  {
22615                 node.removeAttribute(a.name);
22616                 continue;
22617             }
22618             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22619                 node.removeAttribute(a.name);
22620                 continue;
22621             }
22622             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22623                 cleanAttr(a.name,a.value); // fixme..
22624                 continue;
22625             }
22626             if (a.name == 'style') {
22627                 cleanStyle(a.name,a.value);
22628                 continue;
22629             }
22630             /// clean up MS crap..
22631             // tecnically this should be a list of valid class'es..
22632             
22633             
22634             if (a.name == 'class') {
22635                 if (a.value.match(/^Mso/)) {
22636                     node.className = '';
22637                 }
22638                 
22639                 if (a.value.match(/^body$/)) {
22640                     node.className = '';
22641                 }
22642                 continue;
22643             }
22644             
22645             // style cleanup!?
22646             // class cleanup?
22647             
22648         }
22649         
22650         
22651         this.cleanUpChildren(node);
22652         
22653         
22654     },
22655     
22656     /**
22657      * Clean up MS wordisms...
22658      */
22659     cleanWord : function(node)
22660     {
22661         
22662         
22663         if (!node) {
22664             this.cleanWord(this.doc.body);
22665             return;
22666         }
22667         if (node.nodeName == "#text") {
22668             // clean up silly Windows -- stuff?
22669             return; 
22670         }
22671         if (node.nodeName == "#comment") {
22672             node.parentNode.removeChild(node);
22673             // clean up silly Windows -- stuff?
22674             return; 
22675         }
22676         
22677         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22678             node.parentNode.removeChild(node);
22679             return;
22680         }
22681         
22682         // remove - but keep children..
22683         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22684             while (node.childNodes.length) {
22685                 var cn = node.childNodes[0];
22686                 node.removeChild(cn);
22687                 node.parentNode.insertBefore(cn, node);
22688             }
22689             node.parentNode.removeChild(node);
22690             this.iterateChildren(node, this.cleanWord);
22691             return;
22692         }
22693         // clean styles
22694         if (node.className.length) {
22695             
22696             var cn = node.className.split(/\W+/);
22697             var cna = [];
22698             Roo.each(cn, function(cls) {
22699                 if (cls.match(/Mso[a-zA-Z]+/)) {
22700                     return;
22701                 }
22702                 cna.push(cls);
22703             });
22704             node.className = cna.length ? cna.join(' ') : '';
22705             if (!cna.length) {
22706                 node.removeAttribute("class");
22707             }
22708         }
22709         
22710         if (node.hasAttribute("lang")) {
22711             node.removeAttribute("lang");
22712         }
22713         
22714         if (node.hasAttribute("style")) {
22715             
22716             var styles = node.getAttribute("style").split(";");
22717             var nstyle = [];
22718             Roo.each(styles, function(s) {
22719                 if (!s.match(/:/)) {
22720                     return;
22721                 }
22722                 var kv = s.split(":");
22723                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22724                     return;
22725                 }
22726                 // what ever is left... we allow.
22727                 nstyle.push(s);
22728             });
22729             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22730             if (!nstyle.length) {
22731                 node.removeAttribute('style');
22732             }
22733         }
22734         this.iterateChildren(node, this.cleanWord);
22735         
22736         
22737         
22738     },
22739     /**
22740      * iterateChildren of a Node, calling fn each time, using this as the scole..
22741      * @param {DomNode} node node to iterate children of.
22742      * @param {Function} fn method of this class to call on each item.
22743      */
22744     iterateChildren : function(node, fn)
22745     {
22746         if (!node.childNodes.length) {
22747                 return;
22748         }
22749         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22750            fn.call(this, node.childNodes[i])
22751         }
22752     },
22753     
22754     
22755     /**
22756      * cleanTableWidths.
22757      *
22758      * Quite often pasting from word etc.. results in tables with column and widths.
22759      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22760      *
22761      */
22762     cleanTableWidths : function(node)
22763     {
22764          
22765          
22766         if (!node) {
22767             this.cleanTableWidths(this.doc.body);
22768             return;
22769         }
22770         
22771         // ignore list...
22772         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22773             return; 
22774         }
22775         Roo.log(node.tagName);
22776         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22777             this.iterateChildren(node, this.cleanTableWidths);
22778             return;
22779         }
22780         if (node.hasAttribute('width')) {
22781             node.removeAttribute('width');
22782         }
22783         
22784          
22785         if (node.hasAttribute("style")) {
22786             // pretty basic...
22787             
22788             var styles = node.getAttribute("style").split(";");
22789             var nstyle = [];
22790             Roo.each(styles, function(s) {
22791                 if (!s.match(/:/)) {
22792                     return;
22793                 }
22794                 var kv = s.split(":");
22795                 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22796                     return;
22797                 }
22798                 // what ever is left... we allow.
22799                 nstyle.push(s);
22800             });
22801             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22802             if (!nstyle.length) {
22803                 node.removeAttribute('style');
22804             }
22805         }
22806         
22807         this.iterateChildren(node, this.cleanTableWidths);
22808         
22809         
22810     },
22811     
22812     
22813     
22814     
22815     domToHTML : function(currentElement, depth, nopadtext) {
22816         
22817         depth = depth || 0;
22818         nopadtext = nopadtext || false;
22819     
22820         if (!currentElement) {
22821             return this.domToHTML(this.doc.body);
22822         }
22823         
22824         //Roo.log(currentElement);
22825         var j;
22826         var allText = false;
22827         var nodeName = currentElement.nodeName;
22828         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22829         
22830         if  (nodeName == '#text') {
22831             
22832             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22833         }
22834         
22835         
22836         var ret = '';
22837         if (nodeName != 'BODY') {
22838              
22839             var i = 0;
22840             // Prints the node tagName, such as <A>, <IMG>, etc
22841             if (tagName) {
22842                 var attr = [];
22843                 for(i = 0; i < currentElement.attributes.length;i++) {
22844                     // quoting?
22845                     var aname = currentElement.attributes.item(i).name;
22846                     if (!currentElement.attributes.item(i).value.length) {
22847                         continue;
22848                     }
22849                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22850                 }
22851                 
22852                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22853             } 
22854             else {
22855                 
22856                 // eack
22857             }
22858         } else {
22859             tagName = false;
22860         }
22861         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22862             return ret;
22863         }
22864         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22865             nopadtext = true;
22866         }
22867         
22868         
22869         // Traverse the tree
22870         i = 0;
22871         var currentElementChild = currentElement.childNodes.item(i);
22872         var allText = true;
22873         var innerHTML  = '';
22874         lastnode = '';
22875         while (currentElementChild) {
22876             // Formatting code (indent the tree so it looks nice on the screen)
22877             var nopad = nopadtext;
22878             if (lastnode == 'SPAN') {
22879                 nopad  = true;
22880             }
22881             // text
22882             if  (currentElementChild.nodeName == '#text') {
22883                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22884                 toadd = nopadtext ? toadd : toadd.trim();
22885                 if (!nopad && toadd.length > 80) {
22886                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22887                 }
22888                 innerHTML  += toadd;
22889                 
22890                 i++;
22891                 currentElementChild = currentElement.childNodes.item(i);
22892                 lastNode = '';
22893                 continue;
22894             }
22895             allText = false;
22896             
22897             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22898                 
22899             // Recursively traverse the tree structure of the child node
22900             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22901             lastnode = currentElementChild.nodeName;
22902             i++;
22903             currentElementChild=currentElement.childNodes.item(i);
22904         }
22905         
22906         ret += innerHTML;
22907         
22908         if (!allText) {
22909                 // The remaining code is mostly for formatting the tree
22910             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22911         }
22912         
22913         
22914         if (tagName) {
22915             ret+= "</"+tagName+">";
22916         }
22917         return ret;
22918         
22919     },
22920         
22921     applyBlacklists : function()
22922     {
22923         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22924         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22925         
22926         this.white = [];
22927         this.black = [];
22928         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22929             if (b.indexOf(tag) > -1) {
22930                 return;
22931             }
22932             this.white.push(tag);
22933             
22934         }, this);
22935         
22936         Roo.each(w, function(tag) {
22937             if (b.indexOf(tag) > -1) {
22938                 return;
22939             }
22940             if (this.white.indexOf(tag) > -1) {
22941                 return;
22942             }
22943             this.white.push(tag);
22944             
22945         }, this);
22946         
22947         
22948         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22949             if (w.indexOf(tag) > -1) {
22950                 return;
22951             }
22952             this.black.push(tag);
22953             
22954         }, this);
22955         
22956         Roo.each(b, function(tag) {
22957             if (w.indexOf(tag) > -1) {
22958                 return;
22959             }
22960             if (this.black.indexOf(tag) > -1) {
22961                 return;
22962             }
22963             this.black.push(tag);
22964             
22965         }, this);
22966         
22967         
22968         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22969         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22970         
22971         this.cwhite = [];
22972         this.cblack = [];
22973         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22974             if (b.indexOf(tag) > -1) {
22975                 return;
22976             }
22977             this.cwhite.push(tag);
22978             
22979         }, this);
22980         
22981         Roo.each(w, function(tag) {
22982             if (b.indexOf(tag) > -1) {
22983                 return;
22984             }
22985             if (this.cwhite.indexOf(tag) > -1) {
22986                 return;
22987             }
22988             this.cwhite.push(tag);
22989             
22990         }, this);
22991         
22992         
22993         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22994             if (w.indexOf(tag) > -1) {
22995                 return;
22996             }
22997             this.cblack.push(tag);
22998             
22999         }, this);
23000         
23001         Roo.each(b, function(tag) {
23002             if (w.indexOf(tag) > -1) {
23003                 return;
23004             }
23005             if (this.cblack.indexOf(tag) > -1) {
23006                 return;
23007             }
23008             this.cblack.push(tag);
23009             
23010         }, this);
23011     },
23012     
23013     setStylesheets : function(stylesheets)
23014     {
23015         if(typeof(stylesheets) == 'string'){
23016             Roo.get(this.iframe.contentDocument.head).createChild({
23017                 tag : 'link',
23018                 rel : 'stylesheet',
23019                 type : 'text/css',
23020                 href : stylesheets
23021             });
23022             
23023             return;
23024         }
23025         var _this = this;
23026      
23027         Roo.each(stylesheets, function(s) {
23028             if(!s.length){
23029                 return;
23030             }
23031             
23032             Roo.get(_this.iframe.contentDocument.head).createChild({
23033                 tag : 'link',
23034                 rel : 'stylesheet',
23035                 type : 'text/css',
23036                 href : s
23037             });
23038         });
23039
23040         
23041     },
23042     
23043     removeStylesheets : function()
23044     {
23045         var _this = this;
23046         
23047         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23048             s.remove();
23049         });
23050     },
23051     
23052     setStyle : function(style)
23053     {
23054         Roo.get(this.iframe.contentDocument.head).createChild({
23055             tag : 'style',
23056             type : 'text/css',
23057             html : style
23058         });
23059
23060         return;
23061     }
23062     
23063     // hide stuff that is not compatible
23064     /**
23065      * @event blur
23066      * @hide
23067      */
23068     /**
23069      * @event change
23070      * @hide
23071      */
23072     /**
23073      * @event focus
23074      * @hide
23075      */
23076     /**
23077      * @event specialkey
23078      * @hide
23079      */
23080     /**
23081      * @cfg {String} fieldClass @hide
23082      */
23083     /**
23084      * @cfg {String} focusClass @hide
23085      */
23086     /**
23087      * @cfg {String} autoCreate @hide
23088      */
23089     /**
23090      * @cfg {String} inputType @hide
23091      */
23092     /**
23093      * @cfg {String} invalidClass @hide
23094      */
23095     /**
23096      * @cfg {String} invalidText @hide
23097      */
23098     /**
23099      * @cfg {String} msgFx @hide
23100      */
23101     /**
23102      * @cfg {String} validateOnBlur @hide
23103      */
23104 });
23105
23106 Roo.HtmlEditorCore.white = [
23107         'area', 'br', 'img', 'input', 'hr', 'wbr',
23108         
23109        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
23110        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
23111        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
23112        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
23113        'table',   'ul',         'xmp', 
23114        
23115        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
23116       'thead',   'tr', 
23117      
23118       'dir', 'menu', 'ol', 'ul', 'dl',
23119        
23120       'embed',  'object'
23121 ];
23122
23123
23124 Roo.HtmlEditorCore.black = [
23125     //    'embed',  'object', // enable - backend responsiblity to clean thiese
23126         'applet', // 
23127         'base',   'basefont', 'bgsound', 'blink',  'body', 
23128         'frame',  'frameset', 'head',    'html',   'ilayer', 
23129         'iframe', 'layer',  'link',     'meta',    'object',   
23130         'script', 'style' ,'title',  'xml' // clean later..
23131 ];
23132 Roo.HtmlEditorCore.clean = [
23133     'script', 'style', 'title', 'xml'
23134 ];
23135 Roo.HtmlEditorCore.remove = [
23136     'font'
23137 ];
23138 // attributes..
23139
23140 Roo.HtmlEditorCore.ablack = [
23141     'on'
23142 ];
23143     
23144 Roo.HtmlEditorCore.aclean = [ 
23145     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
23146 ];
23147
23148 // protocols..
23149 Roo.HtmlEditorCore.pwhite= [
23150         'http',  'https',  'mailto'
23151 ];
23152
23153 // white listed style attributes.
23154 Roo.HtmlEditorCore.cwhite= [
23155       //  'text-align', /// default is to allow most things..
23156       
23157          
23158 //        'font-size'//??
23159 ];
23160
23161 // black listed style attributes.
23162 Roo.HtmlEditorCore.cblack= [
23163       //  'font-size' -- this can be set by the project 
23164 ];
23165
23166
23167 Roo.HtmlEditorCore.swapCodes   =[ 
23168     [    8211, "--" ], 
23169     [    8212, "--" ], 
23170     [    8216,  "'" ],  
23171     [    8217, "'" ],  
23172     [    8220, '"' ],  
23173     [    8221, '"' ],  
23174     [    8226, "*" ],  
23175     [    8230, "..." ]
23176 ]; 
23177
23178     /*
23179  * - LGPL
23180  *
23181  * HtmlEditor
23182  * 
23183  */
23184
23185 /**
23186  * @class Roo.bootstrap.HtmlEditor
23187  * @extends Roo.bootstrap.TextArea
23188  * Bootstrap HtmlEditor class
23189
23190  * @constructor
23191  * Create a new HtmlEditor
23192  * @param {Object} config The config object
23193  */
23194
23195 Roo.bootstrap.HtmlEditor = function(config){
23196     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23197     if (!this.toolbars) {
23198         this.toolbars = [];
23199     }
23200     
23201     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23202     this.addEvents({
23203             /**
23204              * @event initialize
23205              * Fires when the editor is fully initialized (including the iframe)
23206              * @param {HtmlEditor} this
23207              */
23208             initialize: true,
23209             /**
23210              * @event activate
23211              * Fires when the editor is first receives the focus. Any insertion must wait
23212              * until after this event.
23213              * @param {HtmlEditor} this
23214              */
23215             activate: true,
23216              /**
23217              * @event beforesync
23218              * Fires before the textarea is updated with content from the editor iframe. Return false
23219              * to cancel the sync.
23220              * @param {HtmlEditor} this
23221              * @param {String} html
23222              */
23223             beforesync: true,
23224              /**
23225              * @event beforepush
23226              * Fires before the iframe editor is updated with content from the textarea. Return false
23227              * to cancel the push.
23228              * @param {HtmlEditor} this
23229              * @param {String} html
23230              */
23231             beforepush: true,
23232              /**
23233              * @event sync
23234              * Fires when the textarea is updated with content from the editor iframe.
23235              * @param {HtmlEditor} this
23236              * @param {String} html
23237              */
23238             sync: true,
23239              /**
23240              * @event push
23241              * Fires when the iframe editor is updated with content from the textarea.
23242              * @param {HtmlEditor} this
23243              * @param {String} html
23244              */
23245             push: true,
23246              /**
23247              * @event editmodechange
23248              * Fires when the editor switches edit modes
23249              * @param {HtmlEditor} this
23250              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23251              */
23252             editmodechange: true,
23253             /**
23254              * @event editorevent
23255              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23256              * @param {HtmlEditor} this
23257              */
23258             editorevent: true,
23259             /**
23260              * @event firstfocus
23261              * Fires when on first focus - needed by toolbars..
23262              * @param {HtmlEditor} this
23263              */
23264             firstfocus: true,
23265             /**
23266              * @event autosave
23267              * Auto save the htmlEditor value as a file into Events
23268              * @param {HtmlEditor} this
23269              */
23270             autosave: true,
23271             /**
23272              * @event savedpreview
23273              * preview the saved version of htmlEditor
23274              * @param {HtmlEditor} this
23275              */
23276             savedpreview: true
23277         });
23278 };
23279
23280
23281 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23282     
23283     
23284       /**
23285      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23286      */
23287     toolbars : false,
23288     
23289      /**
23290     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23291     */
23292     btns : [],
23293    
23294      /**
23295      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23296      *                        Roo.resizable.
23297      */
23298     resizable : false,
23299      /**
23300      * @cfg {Number} height (in pixels)
23301      */   
23302     height: 300,
23303    /**
23304      * @cfg {Number} width (in pixels)
23305      */   
23306     width: false,
23307     
23308     /**
23309      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23310      * 
23311      */
23312     stylesheets: false,
23313     
23314     // id of frame..
23315     frameId: false,
23316     
23317     // private properties
23318     validationEvent : false,
23319     deferHeight: true,
23320     initialized : false,
23321     activated : false,
23322     
23323     onFocus : Roo.emptyFn,
23324     iframePad:3,
23325     hideMode:'offsets',
23326     
23327     tbContainer : false,
23328     
23329     bodyCls : '',
23330     
23331     toolbarContainer :function() {
23332         return this.wrap.select('.x-html-editor-tb',true).first();
23333     },
23334
23335     /**
23336      * Protected method that will not generally be called directly. It
23337      * is called when the editor creates its toolbar. Override this method if you need to
23338      * add custom toolbar buttons.
23339      * @param {HtmlEditor} editor
23340      */
23341     createToolbar : function(){
23342         Roo.log('renewing');
23343         Roo.log("create toolbars");
23344         
23345         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23346         this.toolbars[0].render(this.toolbarContainer());
23347         
23348         return;
23349         
23350 //        if (!editor.toolbars || !editor.toolbars.length) {
23351 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23352 //        }
23353 //        
23354 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23355 //            editor.toolbars[i] = Roo.factory(
23356 //                    typeof(editor.toolbars[i]) == 'string' ?
23357 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23358 //                Roo.bootstrap.HtmlEditor);
23359 //            editor.toolbars[i].init(editor);
23360 //        }
23361     },
23362
23363      
23364     // private
23365     onRender : function(ct, position)
23366     {
23367        // Roo.log("Call onRender: " + this.xtype);
23368         var _t = this;
23369         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23370       
23371         this.wrap = this.inputEl().wrap({
23372             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23373         });
23374         
23375         this.editorcore.onRender(ct, position);
23376          
23377         if (this.resizable) {
23378             this.resizeEl = new Roo.Resizable(this.wrap, {
23379                 pinned : true,
23380                 wrap: true,
23381                 dynamic : true,
23382                 minHeight : this.height,
23383                 height: this.height,
23384                 handles : this.resizable,
23385                 width: this.width,
23386                 listeners : {
23387                     resize : function(r, w, h) {
23388                         _t.onResize(w,h); // -something
23389                     }
23390                 }
23391             });
23392             
23393         }
23394         this.createToolbar(this);
23395        
23396         
23397         if(!this.width && this.resizable){
23398             this.setSize(this.wrap.getSize());
23399         }
23400         if (this.resizeEl) {
23401             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23402             // should trigger onReize..
23403         }
23404         
23405     },
23406
23407     // private
23408     onResize : function(w, h)
23409     {
23410         Roo.log('resize: ' +w + ',' + h );
23411         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23412         var ew = false;
23413         var eh = false;
23414         
23415         if(this.inputEl() ){
23416             if(typeof w == 'number'){
23417                 var aw = w - this.wrap.getFrameWidth('lr');
23418                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23419                 ew = aw;
23420             }
23421             if(typeof h == 'number'){
23422                  var tbh = -11;  // fixme it needs to tool bar size!
23423                 for (var i =0; i < this.toolbars.length;i++) {
23424                     // fixme - ask toolbars for heights?
23425                     tbh += this.toolbars[i].el.getHeight();
23426                     //if (this.toolbars[i].footer) {
23427                     //    tbh += this.toolbars[i].footer.el.getHeight();
23428                     //}
23429                 }
23430               
23431                 
23432                 
23433                 
23434                 
23435                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23436                 ah -= 5; // knock a few pixes off for look..
23437                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23438                 var eh = ah;
23439             }
23440         }
23441         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23442         this.editorcore.onResize(ew,eh);
23443         
23444     },
23445
23446     /**
23447      * Toggles the editor between standard and source edit mode.
23448      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23449      */
23450     toggleSourceEdit : function(sourceEditMode)
23451     {
23452         this.editorcore.toggleSourceEdit(sourceEditMode);
23453         
23454         if(this.editorcore.sourceEditMode){
23455             Roo.log('editor - showing textarea');
23456             
23457 //            Roo.log('in');
23458 //            Roo.log(this.syncValue());
23459             this.syncValue();
23460             this.inputEl().removeClass(['hide', 'x-hidden']);
23461             this.inputEl().dom.removeAttribute('tabIndex');
23462             this.inputEl().focus();
23463         }else{
23464             Roo.log('editor - hiding textarea');
23465 //            Roo.log('out')
23466 //            Roo.log(this.pushValue()); 
23467             this.pushValue();
23468             
23469             this.inputEl().addClass(['hide', 'x-hidden']);
23470             this.inputEl().dom.setAttribute('tabIndex', -1);
23471             //this.deferFocus();
23472         }
23473          
23474         if(this.resizable){
23475             this.setSize(this.wrap.getSize());
23476         }
23477         
23478         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23479     },
23480  
23481     // private (for BoxComponent)
23482     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23483
23484     // private (for BoxComponent)
23485     getResizeEl : function(){
23486         return this.wrap;
23487     },
23488
23489     // private (for BoxComponent)
23490     getPositionEl : function(){
23491         return this.wrap;
23492     },
23493
23494     // private
23495     initEvents : function(){
23496         this.originalValue = this.getValue();
23497     },
23498
23499 //    /**
23500 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23501 //     * @method
23502 //     */
23503 //    markInvalid : Roo.emptyFn,
23504 //    /**
23505 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23506 //     * @method
23507 //     */
23508 //    clearInvalid : Roo.emptyFn,
23509
23510     setValue : function(v){
23511         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23512         this.editorcore.pushValue();
23513     },
23514
23515      
23516     // private
23517     deferFocus : function(){
23518         this.focus.defer(10, this);
23519     },
23520
23521     // doc'ed in Field
23522     focus : function(){
23523         this.editorcore.focus();
23524         
23525     },
23526       
23527
23528     // private
23529     onDestroy : function(){
23530         
23531         
23532         
23533         if(this.rendered){
23534             
23535             for (var i =0; i < this.toolbars.length;i++) {
23536                 // fixme - ask toolbars for heights?
23537                 this.toolbars[i].onDestroy();
23538             }
23539             
23540             this.wrap.dom.innerHTML = '';
23541             this.wrap.remove();
23542         }
23543     },
23544
23545     // private
23546     onFirstFocus : function(){
23547         //Roo.log("onFirstFocus");
23548         this.editorcore.onFirstFocus();
23549          for (var i =0; i < this.toolbars.length;i++) {
23550             this.toolbars[i].onFirstFocus();
23551         }
23552         
23553     },
23554     
23555     // private
23556     syncValue : function()
23557     {   
23558         this.editorcore.syncValue();
23559     },
23560     
23561     pushValue : function()
23562     {   
23563         this.editorcore.pushValue();
23564     }
23565      
23566     
23567     // hide stuff that is not compatible
23568     /**
23569      * @event blur
23570      * @hide
23571      */
23572     /**
23573      * @event change
23574      * @hide
23575      */
23576     /**
23577      * @event focus
23578      * @hide
23579      */
23580     /**
23581      * @event specialkey
23582      * @hide
23583      */
23584     /**
23585      * @cfg {String} fieldClass @hide
23586      */
23587     /**
23588      * @cfg {String} focusClass @hide
23589      */
23590     /**
23591      * @cfg {String} autoCreate @hide
23592      */
23593     /**
23594      * @cfg {String} inputType @hide
23595      */
23596     /**
23597      * @cfg {String} invalidClass @hide
23598      */
23599     /**
23600      * @cfg {String} invalidText @hide
23601      */
23602     /**
23603      * @cfg {String} msgFx @hide
23604      */
23605     /**
23606      * @cfg {String} validateOnBlur @hide
23607      */
23608 });
23609  
23610     
23611    
23612    
23613    
23614       
23615 Roo.namespace('Roo.bootstrap.htmleditor');
23616 /**
23617  * @class Roo.bootstrap.HtmlEditorToolbar1
23618  * Basic Toolbar
23619  * 
23620  * Usage:
23621  *
23622  new Roo.bootstrap.HtmlEditor({
23623     ....
23624     toolbars : [
23625         new Roo.bootstrap.HtmlEditorToolbar1({
23626             disable : { fonts: 1 , format: 1, ..., ... , ...],
23627             btns : [ .... ]
23628         })
23629     }
23630      
23631  * 
23632  * @cfg {Object} disable List of elements to disable..
23633  * @cfg {Array} btns List of additional buttons.
23634  * 
23635  * 
23636  * NEEDS Extra CSS? 
23637  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23638  */
23639  
23640 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23641 {
23642     
23643     Roo.apply(this, config);
23644     
23645     // default disabled, based on 'good practice'..
23646     this.disable = this.disable || {};
23647     Roo.applyIf(this.disable, {
23648         fontSize : true,
23649         colors : true,
23650         specialElements : true
23651     });
23652     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23653     
23654     this.editor = config.editor;
23655     this.editorcore = config.editor.editorcore;
23656     
23657     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23658     
23659     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23660     // dont call parent... till later.
23661 }
23662 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23663      
23664     bar : true,
23665     
23666     editor : false,
23667     editorcore : false,
23668     
23669     
23670     formats : [
23671         "p" ,  
23672         "h1","h2","h3","h4","h5","h6", 
23673         "pre", "code", 
23674         "abbr", "acronym", "address", "cite", "samp", "var",
23675         'div','span'
23676     ],
23677     
23678     onRender : function(ct, position)
23679     {
23680        // Roo.log("Call onRender: " + this.xtype);
23681         
23682        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23683        Roo.log(this.el);
23684        this.el.dom.style.marginBottom = '0';
23685        var _this = this;
23686        var editorcore = this.editorcore;
23687        var editor= this.editor;
23688        
23689        var children = [];
23690        var btn = function(id,cmd , toggle, handler, html){
23691        
23692             var  event = toggle ? 'toggle' : 'click';
23693        
23694             var a = {
23695                 size : 'sm',
23696                 xtype: 'Button',
23697                 xns: Roo.bootstrap,
23698                 glyphicon : id,
23699                 cmd : id || cmd,
23700                 enableToggle:toggle !== false,
23701                 html : html || '',
23702                 pressed : toggle ? false : null,
23703                 listeners : {}
23704             };
23705             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23706                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23707             };
23708             children.push(a);
23709             return a;
23710        }
23711        
23712     //    var cb_box = function...
23713         
23714         var style = {
23715                 xtype: 'Button',
23716                 size : 'sm',
23717                 xns: Roo.bootstrap,
23718                 glyphicon : 'font',
23719                 //html : 'submit'
23720                 menu : {
23721                     xtype: 'Menu',
23722                     xns: Roo.bootstrap,
23723                     items:  []
23724                 }
23725         };
23726         Roo.each(this.formats, function(f) {
23727             style.menu.items.push({
23728                 xtype :'MenuItem',
23729                 xns: Roo.bootstrap,
23730                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23731                 tagname : f,
23732                 listeners : {
23733                     click : function()
23734                     {
23735                         editorcore.insertTag(this.tagname);
23736                         editor.focus();
23737                     }
23738                 }
23739                 
23740             });
23741         });
23742         children.push(style);   
23743         
23744         btn('bold',false,true);
23745         btn('italic',false,true);
23746         btn('align-left', 'justifyleft',true);
23747         btn('align-center', 'justifycenter',true);
23748         btn('align-right' , 'justifyright',true);
23749         btn('link', false, false, function(btn) {
23750             //Roo.log("create link?");
23751             var url = prompt(this.createLinkText, this.defaultLinkValue);
23752             if(url && url != 'http:/'+'/'){
23753                 this.editorcore.relayCmd('createlink', url);
23754             }
23755         }),
23756         btn('list','insertunorderedlist',true);
23757         btn('pencil', false,true, function(btn){
23758                 Roo.log(this);
23759                 this.toggleSourceEdit(btn.pressed);
23760         });
23761         
23762         if (this.editor.btns.length > 0) {
23763             for (var i = 0; i<this.editor.btns.length; i++) {
23764                 children.push(this.editor.btns[i]);
23765             }
23766         }
23767         
23768         /*
23769         var cog = {
23770                 xtype: 'Button',
23771                 size : 'sm',
23772                 xns: Roo.bootstrap,
23773                 glyphicon : 'cog',
23774                 //html : 'submit'
23775                 menu : {
23776                     xtype: 'Menu',
23777                     xns: Roo.bootstrap,
23778                     items:  []
23779                 }
23780         };
23781         
23782         cog.menu.items.push({
23783             xtype :'MenuItem',
23784             xns: Roo.bootstrap,
23785             html : Clean styles,
23786             tagname : f,
23787             listeners : {
23788                 click : function()
23789                 {
23790                     editorcore.insertTag(this.tagname);
23791                     editor.focus();
23792                 }
23793             }
23794             
23795         });
23796        */
23797         
23798          
23799        this.xtype = 'NavSimplebar';
23800         
23801         for(var i=0;i< children.length;i++) {
23802             
23803             this.buttons.add(this.addxtypeChild(children[i]));
23804             
23805         }
23806         
23807         editor.on('editorevent', this.updateToolbar, this);
23808     },
23809     onBtnClick : function(id)
23810     {
23811        this.editorcore.relayCmd(id);
23812        this.editorcore.focus();
23813     },
23814     
23815     /**
23816      * Protected method that will not generally be called directly. It triggers
23817      * a toolbar update by reading the markup state of the current selection in the editor.
23818      */
23819     updateToolbar: function(){
23820
23821         if(!this.editorcore.activated){
23822             this.editor.onFirstFocus(); // is this neeed?
23823             return;
23824         }
23825
23826         var btns = this.buttons; 
23827         var doc = this.editorcore.doc;
23828         btns.get('bold').setActive(doc.queryCommandState('bold'));
23829         btns.get('italic').setActive(doc.queryCommandState('italic'));
23830         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23831         
23832         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23833         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23834         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23835         
23836         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23837         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23838          /*
23839         
23840         var ans = this.editorcore.getAllAncestors();
23841         if (this.formatCombo) {
23842             
23843             
23844             var store = this.formatCombo.store;
23845             this.formatCombo.setValue("");
23846             for (var i =0; i < ans.length;i++) {
23847                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23848                     // select it..
23849                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23850                     break;
23851                 }
23852             }
23853         }
23854         
23855         
23856         
23857         // hides menus... - so this cant be on a menu...
23858         Roo.bootstrap.MenuMgr.hideAll();
23859         */
23860         Roo.bootstrap.MenuMgr.hideAll();
23861         //this.editorsyncValue();
23862     },
23863     onFirstFocus: function() {
23864         this.buttons.each(function(item){
23865            item.enable();
23866         });
23867     },
23868     toggleSourceEdit : function(sourceEditMode){
23869         
23870           
23871         if(sourceEditMode){
23872             Roo.log("disabling buttons");
23873            this.buttons.each( function(item){
23874                 if(item.cmd != 'pencil'){
23875                     item.disable();
23876                 }
23877             });
23878           
23879         }else{
23880             Roo.log("enabling buttons");
23881             if(this.editorcore.initialized){
23882                 this.buttons.each( function(item){
23883                     item.enable();
23884                 });
23885             }
23886             
23887         }
23888         Roo.log("calling toggole on editor");
23889         // tell the editor that it's been pressed..
23890         this.editor.toggleSourceEdit(sourceEditMode);
23891        
23892     }
23893 });
23894
23895
23896
23897
23898
23899 /**
23900  * @class Roo.bootstrap.Table.AbstractSelectionModel
23901  * @extends Roo.util.Observable
23902  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23903  * implemented by descendant classes.  This class should not be directly instantiated.
23904  * @constructor
23905  */
23906 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23907     this.locked = false;
23908     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23909 };
23910
23911
23912 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23913     /** @ignore Called by the grid automatically. Do not call directly. */
23914     init : function(grid){
23915         this.grid = grid;
23916         this.initEvents();
23917     },
23918
23919     /**
23920      * Locks the selections.
23921      */
23922     lock : function(){
23923         this.locked = true;
23924     },
23925
23926     /**
23927      * Unlocks the selections.
23928      */
23929     unlock : function(){
23930         this.locked = false;
23931     },
23932
23933     /**
23934      * Returns true if the selections are locked.
23935      * @return {Boolean}
23936      */
23937     isLocked : function(){
23938         return this.locked;
23939     }
23940 });
23941 /**
23942  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23943  * @class Roo.bootstrap.Table.RowSelectionModel
23944  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23945  * It supports multiple selections and keyboard selection/navigation. 
23946  * @constructor
23947  * @param {Object} config
23948  */
23949
23950 Roo.bootstrap.Table.RowSelectionModel = function(config){
23951     Roo.apply(this, config);
23952     this.selections = new Roo.util.MixedCollection(false, function(o){
23953         return o.id;
23954     });
23955
23956     this.last = false;
23957     this.lastActive = false;
23958
23959     this.addEvents({
23960         /**
23961              * @event selectionchange
23962              * Fires when the selection changes
23963              * @param {SelectionModel} this
23964              */
23965             "selectionchange" : true,
23966         /**
23967              * @event afterselectionchange
23968              * Fires after the selection changes (eg. by key press or clicking)
23969              * @param {SelectionModel} this
23970              */
23971             "afterselectionchange" : true,
23972         /**
23973              * @event beforerowselect
23974              * Fires when a row is selected being selected, return false to cancel.
23975              * @param {SelectionModel} this
23976              * @param {Number} rowIndex The selected index
23977              * @param {Boolean} keepExisting False if other selections will be cleared
23978              */
23979             "beforerowselect" : true,
23980         /**
23981              * @event rowselect
23982              * Fires when a row is selected.
23983              * @param {SelectionModel} this
23984              * @param {Number} rowIndex The selected index
23985              * @param {Roo.data.Record} r The record
23986              */
23987             "rowselect" : true,
23988         /**
23989              * @event rowdeselect
23990              * Fires when a row is deselected.
23991              * @param {SelectionModel} this
23992              * @param {Number} rowIndex The selected index
23993              */
23994         "rowdeselect" : true
23995     });
23996     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23997     this.locked = false;
23998  };
23999
24000 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
24001     /**
24002      * @cfg {Boolean} singleSelect
24003      * True to allow selection of only one row at a time (defaults to false)
24004      */
24005     singleSelect : false,
24006
24007     // private
24008     initEvents : function()
24009     {
24010
24011         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24012         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
24013         //}else{ // allow click to work like normal
24014          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
24015         //}
24016         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24017         this.grid.on("rowclick", this.handleMouseDown, this);
24018         
24019         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24020             "up" : function(e){
24021                 if(!e.shiftKey){
24022                     this.selectPrevious(e.shiftKey);
24023                 }else if(this.last !== false && this.lastActive !== false){
24024                     var last = this.last;
24025                     this.selectRange(this.last,  this.lastActive-1);
24026                     this.grid.getView().focusRow(this.lastActive);
24027                     if(last !== false){
24028                         this.last = last;
24029                     }
24030                 }else{
24031                     this.selectFirstRow();
24032                 }
24033                 this.fireEvent("afterselectionchange", this);
24034             },
24035             "down" : function(e){
24036                 if(!e.shiftKey){
24037                     this.selectNext(e.shiftKey);
24038                 }else if(this.last !== false && this.lastActive !== false){
24039                     var last = this.last;
24040                     this.selectRange(this.last,  this.lastActive+1);
24041                     this.grid.getView().focusRow(this.lastActive);
24042                     if(last !== false){
24043                         this.last = last;
24044                     }
24045                 }else{
24046                     this.selectFirstRow();
24047                 }
24048                 this.fireEvent("afterselectionchange", this);
24049             },
24050             scope: this
24051         });
24052         this.grid.store.on('load', function(){
24053             this.selections.clear();
24054         },this);
24055         /*
24056         var view = this.grid.view;
24057         view.on("refresh", this.onRefresh, this);
24058         view.on("rowupdated", this.onRowUpdated, this);
24059         view.on("rowremoved", this.onRemove, this);
24060         */
24061     },
24062
24063     // private
24064     onRefresh : function()
24065     {
24066         var ds = this.grid.store, i, v = this.grid.view;
24067         var s = this.selections;
24068         s.each(function(r){
24069             if((i = ds.indexOfId(r.id)) != -1){
24070                 v.onRowSelect(i);
24071             }else{
24072                 s.remove(r);
24073             }
24074         });
24075     },
24076
24077     // private
24078     onRemove : function(v, index, r){
24079         this.selections.remove(r);
24080     },
24081
24082     // private
24083     onRowUpdated : function(v, index, r){
24084         if(this.isSelected(r)){
24085             v.onRowSelect(index);
24086         }
24087     },
24088
24089     /**
24090      * Select records.
24091      * @param {Array} records The records to select
24092      * @param {Boolean} keepExisting (optional) True to keep existing selections
24093      */
24094     selectRecords : function(records, keepExisting)
24095     {
24096         if(!keepExisting){
24097             this.clearSelections();
24098         }
24099             var ds = this.grid.store;
24100         for(var i = 0, len = records.length; i < len; i++){
24101             this.selectRow(ds.indexOf(records[i]), true);
24102         }
24103     },
24104
24105     /**
24106      * Gets the number of selected rows.
24107      * @return {Number}
24108      */
24109     getCount : function(){
24110         return this.selections.length;
24111     },
24112
24113     /**
24114      * Selects the first row in the grid.
24115      */
24116     selectFirstRow : function(){
24117         this.selectRow(0);
24118     },
24119
24120     /**
24121      * Select the last row.
24122      * @param {Boolean} keepExisting (optional) True to keep existing selections
24123      */
24124     selectLastRow : function(keepExisting){
24125         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24126         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24127     },
24128
24129     /**
24130      * Selects the row immediately following the last selected row.
24131      * @param {Boolean} keepExisting (optional) True to keep existing selections
24132      */
24133     selectNext : function(keepExisting)
24134     {
24135             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24136             this.selectRow(this.last+1, keepExisting);
24137             this.grid.getView().focusRow(this.last);
24138         }
24139     },
24140
24141     /**
24142      * Selects the row that precedes the last selected row.
24143      * @param {Boolean} keepExisting (optional) True to keep existing selections
24144      */
24145     selectPrevious : function(keepExisting){
24146         if(this.last){
24147             this.selectRow(this.last-1, keepExisting);
24148             this.grid.getView().focusRow(this.last);
24149         }
24150     },
24151
24152     /**
24153      * Returns the selected records
24154      * @return {Array} Array of selected records
24155      */
24156     getSelections : function(){
24157         return [].concat(this.selections.items);
24158     },
24159
24160     /**
24161      * Returns the first selected record.
24162      * @return {Record}
24163      */
24164     getSelected : function(){
24165         return this.selections.itemAt(0);
24166     },
24167
24168
24169     /**
24170      * Clears all selections.
24171      */
24172     clearSelections : function(fast)
24173     {
24174         if(this.locked) {
24175             return;
24176         }
24177         if(fast !== true){
24178                 var ds = this.grid.store;
24179             var s = this.selections;
24180             s.each(function(r){
24181                 this.deselectRow(ds.indexOfId(r.id));
24182             }, this);
24183             s.clear();
24184         }else{
24185             this.selections.clear();
24186         }
24187         this.last = false;
24188     },
24189
24190
24191     /**
24192      * Selects all rows.
24193      */
24194     selectAll : function(){
24195         if(this.locked) {
24196             return;
24197         }
24198         this.selections.clear();
24199         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24200             this.selectRow(i, true);
24201         }
24202     },
24203
24204     /**
24205      * Returns True if there is a selection.
24206      * @return {Boolean}
24207      */
24208     hasSelection : function(){
24209         return this.selections.length > 0;
24210     },
24211
24212     /**
24213      * Returns True if the specified row is selected.
24214      * @param {Number/Record} record The record or index of the record to check
24215      * @return {Boolean}
24216      */
24217     isSelected : function(index){
24218             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24219         return (r && this.selections.key(r.id) ? true : false);
24220     },
24221
24222     /**
24223      * Returns True if the specified record id is selected.
24224      * @param {String} id The id of record to check
24225      * @return {Boolean}
24226      */
24227     isIdSelected : function(id){
24228         return (this.selections.key(id) ? true : false);
24229     },
24230
24231
24232     // private
24233     handleMouseDBClick : function(e, t){
24234         
24235     },
24236     // private
24237     handleMouseDown : function(e, t)
24238     {
24239             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24240         if(this.isLocked() || rowIndex < 0 ){
24241             return;
24242         };
24243         if(e.shiftKey && this.last !== false){
24244             var last = this.last;
24245             this.selectRange(last, rowIndex, e.ctrlKey);
24246             this.last = last; // reset the last
24247             t.focus();
24248     
24249         }else{
24250             var isSelected = this.isSelected(rowIndex);
24251             //Roo.log("select row:" + rowIndex);
24252             if(isSelected){
24253                 this.deselectRow(rowIndex);
24254             } else {
24255                         this.selectRow(rowIndex, true);
24256             }
24257     
24258             /*
24259                 if(e.button !== 0 && isSelected){
24260                 alert('rowIndex 2: ' + rowIndex);
24261                     view.focusRow(rowIndex);
24262                 }else if(e.ctrlKey && isSelected){
24263                     this.deselectRow(rowIndex);
24264                 }else if(!isSelected){
24265                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24266                     view.focusRow(rowIndex);
24267                 }
24268             */
24269         }
24270         this.fireEvent("afterselectionchange", this);
24271     },
24272     // private
24273     handleDragableRowClick :  function(grid, rowIndex, e) 
24274     {
24275         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24276             this.selectRow(rowIndex, false);
24277             grid.view.focusRow(rowIndex);
24278              this.fireEvent("afterselectionchange", this);
24279         }
24280     },
24281     
24282     /**
24283      * Selects multiple rows.
24284      * @param {Array} rows Array of the indexes of the row to select
24285      * @param {Boolean} keepExisting (optional) True to keep existing selections
24286      */
24287     selectRows : function(rows, keepExisting){
24288         if(!keepExisting){
24289             this.clearSelections();
24290         }
24291         for(var i = 0, len = rows.length; i < len; i++){
24292             this.selectRow(rows[i], true);
24293         }
24294     },
24295
24296     /**
24297      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24298      * @param {Number} startRow The index of the first row in the range
24299      * @param {Number} endRow The index of the last row in the range
24300      * @param {Boolean} keepExisting (optional) True to retain existing selections
24301      */
24302     selectRange : function(startRow, endRow, keepExisting){
24303         if(this.locked) {
24304             return;
24305         }
24306         if(!keepExisting){
24307             this.clearSelections();
24308         }
24309         if(startRow <= endRow){
24310             for(var i = startRow; i <= endRow; i++){
24311                 this.selectRow(i, true);
24312             }
24313         }else{
24314             for(var i = startRow; i >= endRow; i--){
24315                 this.selectRow(i, true);
24316             }
24317         }
24318     },
24319
24320     /**
24321      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24322      * @param {Number} startRow The index of the first row in the range
24323      * @param {Number} endRow The index of the last row in the range
24324      */
24325     deselectRange : function(startRow, endRow, preventViewNotify){
24326         if(this.locked) {
24327             return;
24328         }
24329         for(var i = startRow; i <= endRow; i++){
24330             this.deselectRow(i, preventViewNotify);
24331         }
24332     },
24333
24334     /**
24335      * Selects a row.
24336      * @param {Number} row The index of the row to select
24337      * @param {Boolean} keepExisting (optional) True to keep existing selections
24338      */
24339     selectRow : function(index, keepExisting, preventViewNotify)
24340     {
24341             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24342             return;
24343         }
24344         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24345             if(!keepExisting || this.singleSelect){
24346                 this.clearSelections();
24347             }
24348             
24349             var r = this.grid.store.getAt(index);
24350             //console.log('selectRow - record id :' + r.id);
24351             
24352             this.selections.add(r);
24353             this.last = this.lastActive = index;
24354             if(!preventViewNotify){
24355                 var proxy = new Roo.Element(
24356                                 this.grid.getRowDom(index)
24357                 );
24358                 proxy.addClass('bg-info info');
24359             }
24360             this.fireEvent("rowselect", this, index, r);
24361             this.fireEvent("selectionchange", this);
24362         }
24363     },
24364
24365     /**
24366      * Deselects a row.
24367      * @param {Number} row The index of the row to deselect
24368      */
24369     deselectRow : function(index, preventViewNotify)
24370     {
24371         if(this.locked) {
24372             return;
24373         }
24374         if(this.last == index){
24375             this.last = false;
24376         }
24377         if(this.lastActive == index){
24378             this.lastActive = false;
24379         }
24380         
24381         var r = this.grid.store.getAt(index);
24382         if (!r) {
24383             return;
24384         }
24385         
24386         this.selections.remove(r);
24387         //.console.log('deselectRow - record id :' + r.id);
24388         if(!preventViewNotify){
24389         
24390             var proxy = new Roo.Element(
24391                 this.grid.getRowDom(index)
24392             );
24393             proxy.removeClass('bg-info info');
24394         }
24395         this.fireEvent("rowdeselect", this, index);
24396         this.fireEvent("selectionchange", this);
24397     },
24398
24399     // private
24400     restoreLast : function(){
24401         if(this._last){
24402             this.last = this._last;
24403         }
24404     },
24405
24406     // private
24407     acceptsNav : function(row, col, cm){
24408         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24409     },
24410
24411     // private
24412     onEditorKey : function(field, e){
24413         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24414         if(k == e.TAB){
24415             e.stopEvent();
24416             ed.completeEdit();
24417             if(e.shiftKey){
24418                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24419             }else{
24420                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24421             }
24422         }else if(k == e.ENTER && !e.ctrlKey){
24423             e.stopEvent();
24424             ed.completeEdit();
24425             if(e.shiftKey){
24426                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24427             }else{
24428                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24429             }
24430         }else if(k == e.ESC){
24431             ed.cancelEdit();
24432         }
24433         if(newCell){
24434             g.startEditing(newCell[0], newCell[1]);
24435         }
24436     }
24437 });
24438 /*
24439  * Based on:
24440  * Ext JS Library 1.1.1
24441  * Copyright(c) 2006-2007, Ext JS, LLC.
24442  *
24443  * Originally Released Under LGPL - original licence link has changed is not relivant.
24444  *
24445  * Fork - LGPL
24446  * <script type="text/javascript">
24447  */
24448  
24449 /**
24450  * @class Roo.bootstrap.PagingToolbar
24451  * @extends Roo.bootstrap.NavSimplebar
24452  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24453  * @constructor
24454  * Create a new PagingToolbar
24455  * @param {Object} config The config object
24456  * @param {Roo.data.Store} store
24457  */
24458 Roo.bootstrap.PagingToolbar = function(config)
24459 {
24460     // old args format still supported... - xtype is prefered..
24461         // created from xtype...
24462     
24463     this.ds = config.dataSource;
24464     
24465     if (config.store && !this.ds) {
24466         this.store= Roo.factory(config.store, Roo.data);
24467         this.ds = this.store;
24468         this.ds.xmodule = this.xmodule || false;
24469     }
24470     
24471     this.toolbarItems = [];
24472     if (config.items) {
24473         this.toolbarItems = config.items;
24474     }
24475     
24476     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24477     
24478     this.cursor = 0;
24479     
24480     if (this.ds) { 
24481         this.bind(this.ds);
24482     }
24483     
24484     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24485     
24486 };
24487
24488 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24489     /**
24490      * @cfg {Roo.data.Store} dataSource
24491      * The underlying data store providing the paged data
24492      */
24493     /**
24494      * @cfg {String/HTMLElement/Element} container
24495      * container The id or element that will contain the toolbar
24496      */
24497     /**
24498      * @cfg {Boolean} displayInfo
24499      * True to display the displayMsg (defaults to false)
24500      */
24501     /**
24502      * @cfg {Number} pageSize
24503      * The number of records to display per page (defaults to 20)
24504      */
24505     pageSize: 20,
24506     /**
24507      * @cfg {String} displayMsg
24508      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24509      */
24510     displayMsg : 'Displaying {0} - {1} of {2}',
24511     /**
24512      * @cfg {String} emptyMsg
24513      * The message to display when no records are found (defaults to "No data to display")
24514      */
24515     emptyMsg : 'No data to display',
24516     /**
24517      * Customizable piece of the default paging text (defaults to "Page")
24518      * @type String
24519      */
24520     beforePageText : "Page",
24521     /**
24522      * Customizable piece of the default paging text (defaults to "of %0")
24523      * @type String
24524      */
24525     afterPageText : "of {0}",
24526     /**
24527      * Customizable piece of the default paging text (defaults to "First Page")
24528      * @type String
24529      */
24530     firstText : "First Page",
24531     /**
24532      * Customizable piece of the default paging text (defaults to "Previous Page")
24533      * @type String
24534      */
24535     prevText : "Previous Page",
24536     /**
24537      * Customizable piece of the default paging text (defaults to "Next Page")
24538      * @type String
24539      */
24540     nextText : "Next Page",
24541     /**
24542      * Customizable piece of the default paging text (defaults to "Last Page")
24543      * @type String
24544      */
24545     lastText : "Last Page",
24546     /**
24547      * Customizable piece of the default paging text (defaults to "Refresh")
24548      * @type String
24549      */
24550     refreshText : "Refresh",
24551
24552     buttons : false,
24553     // private
24554     onRender : function(ct, position) 
24555     {
24556         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24557         this.navgroup.parentId = this.id;
24558         this.navgroup.onRender(this.el, null);
24559         // add the buttons to the navgroup
24560         
24561         if(this.displayInfo){
24562             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24563             this.displayEl = this.el.select('.x-paging-info', true).first();
24564 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24565 //            this.displayEl = navel.el.select('span',true).first();
24566         }
24567         
24568         var _this = this;
24569         
24570         if(this.buttons){
24571             Roo.each(_this.buttons, function(e){ // this might need to use render????
24572                Roo.factory(e).render(_this.el);
24573             });
24574         }
24575             
24576         Roo.each(_this.toolbarItems, function(e) {
24577             _this.navgroup.addItem(e);
24578         });
24579         
24580         
24581         this.first = this.navgroup.addItem({
24582             tooltip: this.firstText,
24583             cls: "prev",
24584             icon : 'fa fa-backward',
24585             disabled: true,
24586             preventDefault: true,
24587             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24588         });
24589         
24590         this.prev =  this.navgroup.addItem({
24591             tooltip: this.prevText,
24592             cls: "prev",
24593             icon : 'fa fa-step-backward',
24594             disabled: true,
24595             preventDefault: true,
24596             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24597         });
24598     //this.addSeparator();
24599         
24600         
24601         var field = this.navgroup.addItem( {
24602             tagtype : 'span',
24603             cls : 'x-paging-position',
24604             
24605             html : this.beforePageText  +
24606                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24607                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24608          } ); //?? escaped?
24609         
24610         this.field = field.el.select('input', true).first();
24611         this.field.on("keydown", this.onPagingKeydown, this);
24612         this.field.on("focus", function(){this.dom.select();});
24613     
24614     
24615         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24616         //this.field.setHeight(18);
24617         //this.addSeparator();
24618         this.next = this.navgroup.addItem({
24619             tooltip: this.nextText,
24620             cls: "next",
24621             html : ' <i class="fa fa-step-forward">',
24622             disabled: true,
24623             preventDefault: true,
24624             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24625         });
24626         this.last = this.navgroup.addItem({
24627             tooltip: this.lastText,
24628             icon : 'fa fa-forward',
24629             cls: "next",
24630             disabled: true,
24631             preventDefault: true,
24632             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24633         });
24634     //this.addSeparator();
24635         this.loading = this.navgroup.addItem({
24636             tooltip: this.refreshText,
24637             icon: 'fa fa-refresh',
24638             preventDefault: true,
24639             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24640         });
24641         
24642     },
24643
24644     // private
24645     updateInfo : function(){
24646         if(this.displayEl){
24647             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24648             var msg = count == 0 ?
24649                 this.emptyMsg :
24650                 String.format(
24651                     this.displayMsg,
24652                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24653                 );
24654             this.displayEl.update(msg);
24655         }
24656     },
24657
24658     // private
24659     onLoad : function(ds, r, o)
24660     {
24661         this.cursor = o.params.start ? o.params.start : 0;
24662         
24663         var d = this.getPageData(),
24664             ap = d.activePage,
24665             ps = d.pages;
24666         
24667         
24668         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24669         this.field.dom.value = ap;
24670         this.first.setDisabled(ap == 1);
24671         this.prev.setDisabled(ap == 1);
24672         this.next.setDisabled(ap == ps);
24673         this.last.setDisabled(ap == ps);
24674         this.loading.enable();
24675         this.updateInfo();
24676     },
24677
24678     // private
24679     getPageData : function(){
24680         var total = this.ds.getTotalCount();
24681         return {
24682             total : total,
24683             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24684             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24685         };
24686     },
24687
24688     // private
24689     onLoadError : function(){
24690         this.loading.enable();
24691     },
24692
24693     // private
24694     onPagingKeydown : function(e){
24695         var k = e.getKey();
24696         var d = this.getPageData();
24697         if(k == e.RETURN){
24698             var v = this.field.dom.value, pageNum;
24699             if(!v || isNaN(pageNum = parseInt(v, 10))){
24700                 this.field.dom.value = d.activePage;
24701                 return;
24702             }
24703             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24704             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24705             e.stopEvent();
24706         }
24707         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))
24708         {
24709           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24710           this.field.dom.value = pageNum;
24711           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24712           e.stopEvent();
24713         }
24714         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24715         {
24716           var v = this.field.dom.value, pageNum; 
24717           var increment = (e.shiftKey) ? 10 : 1;
24718           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24719                 increment *= -1;
24720           }
24721           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24722             this.field.dom.value = d.activePage;
24723             return;
24724           }
24725           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24726           {
24727             this.field.dom.value = parseInt(v, 10) + increment;
24728             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24729             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24730           }
24731           e.stopEvent();
24732         }
24733     },
24734
24735     // private
24736     beforeLoad : function(){
24737         if(this.loading){
24738             this.loading.disable();
24739         }
24740     },
24741
24742     // private
24743     onClick : function(which){
24744         
24745         var ds = this.ds;
24746         if (!ds) {
24747             return;
24748         }
24749         
24750         switch(which){
24751             case "first":
24752                 ds.load({params:{start: 0, limit: this.pageSize}});
24753             break;
24754             case "prev":
24755                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24756             break;
24757             case "next":
24758                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24759             break;
24760             case "last":
24761                 var total = ds.getTotalCount();
24762                 var extra = total % this.pageSize;
24763                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24764                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24765             break;
24766             case "refresh":
24767                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24768             break;
24769         }
24770     },
24771
24772     /**
24773      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24774      * @param {Roo.data.Store} store The data store to unbind
24775      */
24776     unbind : function(ds){
24777         ds.un("beforeload", this.beforeLoad, this);
24778         ds.un("load", this.onLoad, this);
24779         ds.un("loadexception", this.onLoadError, this);
24780         ds.un("remove", this.updateInfo, this);
24781         ds.un("add", this.updateInfo, this);
24782         this.ds = undefined;
24783     },
24784
24785     /**
24786      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24787      * @param {Roo.data.Store} store The data store to bind
24788      */
24789     bind : function(ds){
24790         ds.on("beforeload", this.beforeLoad, this);
24791         ds.on("load", this.onLoad, this);
24792         ds.on("loadexception", this.onLoadError, this);
24793         ds.on("remove", this.updateInfo, this);
24794         ds.on("add", this.updateInfo, this);
24795         this.ds = ds;
24796     }
24797 });/*
24798  * - LGPL
24799  *
24800  * element
24801  * 
24802  */
24803
24804 /**
24805  * @class Roo.bootstrap.MessageBar
24806  * @extends Roo.bootstrap.Component
24807  * Bootstrap MessageBar class
24808  * @cfg {String} html contents of the MessageBar
24809  * @cfg {String} weight (info | success | warning | danger) default info
24810  * @cfg {String} beforeClass insert the bar before the given class
24811  * @cfg {Boolean} closable (true | false) default false
24812  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24813  * 
24814  * @constructor
24815  * Create a new Element
24816  * @param {Object} config The config object
24817  */
24818
24819 Roo.bootstrap.MessageBar = function(config){
24820     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24821 };
24822
24823 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24824     
24825     html: '',
24826     weight: 'info',
24827     closable: false,
24828     fixed: false,
24829     beforeClass: 'bootstrap-sticky-wrap',
24830     
24831     getAutoCreate : function(){
24832         
24833         var cfg = {
24834             tag: 'div',
24835             cls: 'alert alert-dismissable alert-' + this.weight,
24836             cn: [
24837                 {
24838                     tag: 'span',
24839                     cls: 'message',
24840                     html: this.html || ''
24841                 }
24842             ]
24843         };
24844         
24845         if(this.fixed){
24846             cfg.cls += ' alert-messages-fixed';
24847         }
24848         
24849         if(this.closable){
24850             cfg.cn.push({
24851                 tag: 'button',
24852                 cls: 'close',
24853                 html: 'x'
24854             });
24855         }
24856         
24857         return cfg;
24858     },
24859     
24860     onRender : function(ct, position)
24861     {
24862         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24863         
24864         if(!this.el){
24865             var cfg = Roo.apply({},  this.getAutoCreate());
24866             cfg.id = Roo.id();
24867             
24868             if (this.cls) {
24869                 cfg.cls += ' ' + this.cls;
24870             }
24871             if (this.style) {
24872                 cfg.style = this.style;
24873             }
24874             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24875             
24876             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24877         }
24878         
24879         this.el.select('>button.close').on('click', this.hide, this);
24880         
24881     },
24882     
24883     show : function()
24884     {
24885         if (!this.rendered) {
24886             this.render();
24887         }
24888         
24889         this.el.show();
24890         
24891         this.fireEvent('show', this);
24892         
24893     },
24894     
24895     hide : function()
24896     {
24897         if (!this.rendered) {
24898             this.render();
24899         }
24900         
24901         this.el.hide();
24902         
24903         this.fireEvent('hide', this);
24904     },
24905     
24906     update : function()
24907     {
24908 //        var e = this.el.dom.firstChild;
24909 //        
24910 //        if(this.closable){
24911 //            e = e.nextSibling;
24912 //        }
24913 //        
24914 //        e.data = this.html || '';
24915
24916         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24917     }
24918    
24919 });
24920
24921  
24922
24923      /*
24924  * - LGPL
24925  *
24926  * Graph
24927  * 
24928  */
24929
24930
24931 /**
24932  * @class Roo.bootstrap.Graph
24933  * @extends Roo.bootstrap.Component
24934  * Bootstrap Graph class
24935 > Prameters
24936  -sm {number} sm 4
24937  -md {number} md 5
24938  @cfg {String} graphtype  bar | vbar | pie
24939  @cfg {number} g_x coodinator | centre x (pie)
24940  @cfg {number} g_y coodinator | centre y (pie)
24941  @cfg {number} g_r radius (pie)
24942  @cfg {number} g_height height of the chart (respected by all elements in the set)
24943  @cfg {number} g_width width of the chart (respected by all elements in the set)
24944  @cfg {Object} title The title of the chart
24945     
24946  -{Array}  values
24947  -opts (object) options for the chart 
24948      o {
24949      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24950      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24951      o vgutter (number)
24952      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.
24953      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24954      o to
24955      o stretch (boolean)
24956      o }
24957  -opts (object) options for the pie
24958      o{
24959      o cut
24960      o startAngle (number)
24961      o endAngle (number)
24962      } 
24963  *
24964  * @constructor
24965  * Create a new Input
24966  * @param {Object} config The config object
24967  */
24968
24969 Roo.bootstrap.Graph = function(config){
24970     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24971     
24972     this.addEvents({
24973         // img events
24974         /**
24975          * @event click
24976          * The img click event for the img.
24977          * @param {Roo.EventObject} e
24978          */
24979         "click" : true
24980     });
24981 };
24982
24983 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24984     
24985     sm: 4,
24986     md: 5,
24987     graphtype: 'bar',
24988     g_height: 250,
24989     g_width: 400,
24990     g_x: 50,
24991     g_y: 50,
24992     g_r: 30,
24993     opts:{
24994         //g_colors: this.colors,
24995         g_type: 'soft',
24996         g_gutter: '20%'
24997
24998     },
24999     title : false,
25000
25001     getAutoCreate : function(){
25002         
25003         var cfg = {
25004             tag: 'div',
25005             html : null
25006         };
25007         
25008         
25009         return  cfg;
25010     },
25011
25012     onRender : function(ct,position){
25013         
25014         
25015         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25016         
25017         if (typeof(Raphael) == 'undefined') {
25018             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25019             return;
25020         }
25021         
25022         this.raphael = Raphael(this.el.dom);
25023         
25024                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25025                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25026                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25027                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25028                 /*
25029                 r.text(160, 10, "Single Series Chart").attr(txtattr);
25030                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25031                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25032                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25033                 
25034                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25035                 r.barchart(330, 10, 300, 220, data1);
25036                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25037                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25038                 */
25039                 
25040                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25041                 // r.barchart(30, 30, 560, 250,  xdata, {
25042                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25043                 //     axis : "0 0 1 1",
25044                 //     axisxlabels :  xdata
25045                 //     //yvalues : cols,
25046                    
25047                 // });
25048 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25049 //        
25050 //        this.load(null,xdata,{
25051 //                axis : "0 0 1 1",
25052 //                axisxlabels :  xdata
25053 //                });
25054
25055     },
25056
25057     load : function(graphtype,xdata,opts)
25058     {
25059         this.raphael.clear();
25060         if(!graphtype) {
25061             graphtype = this.graphtype;
25062         }
25063         if(!opts){
25064             opts = this.opts;
25065         }
25066         var r = this.raphael,
25067             fin = function () {
25068                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25069             },
25070             fout = function () {
25071                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25072             },
25073             pfin = function() {
25074                 this.sector.stop();
25075                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25076
25077                 if (this.label) {
25078                     this.label[0].stop();
25079                     this.label[0].attr({ r: 7.5 });
25080                     this.label[1].attr({ "font-weight": 800 });
25081                 }
25082             },
25083             pfout = function() {
25084                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25085
25086                 if (this.label) {
25087                     this.label[0].animate({ r: 5 }, 500, "bounce");
25088                     this.label[1].attr({ "font-weight": 400 });
25089                 }
25090             };
25091
25092         switch(graphtype){
25093             case 'bar':
25094                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25095                 break;
25096             case 'hbar':
25097                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25098                 break;
25099             case 'pie':
25100 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
25101 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25102 //            
25103                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25104                 
25105                 break;
25106
25107         }
25108         
25109         if(this.title){
25110             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25111         }
25112         
25113     },
25114     
25115     setTitle: function(o)
25116     {
25117         this.title = o;
25118     },
25119     
25120     initEvents: function() {
25121         
25122         if(!this.href){
25123             this.el.on('click', this.onClick, this);
25124         }
25125     },
25126     
25127     onClick : function(e)
25128     {
25129         Roo.log('img onclick');
25130         this.fireEvent('click', this, e);
25131     }
25132    
25133 });
25134
25135  
25136 /*
25137  * - LGPL
25138  *
25139  * numberBox
25140  * 
25141  */
25142 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25143
25144 /**
25145  * @class Roo.bootstrap.dash.NumberBox
25146  * @extends Roo.bootstrap.Component
25147  * Bootstrap NumberBox class
25148  * @cfg {String} headline Box headline
25149  * @cfg {String} content Box content
25150  * @cfg {String} icon Box icon
25151  * @cfg {String} footer Footer text
25152  * @cfg {String} fhref Footer href
25153  * 
25154  * @constructor
25155  * Create a new NumberBox
25156  * @param {Object} config The config object
25157  */
25158
25159
25160 Roo.bootstrap.dash.NumberBox = function(config){
25161     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25162     
25163 };
25164
25165 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
25166     
25167     headline : '',
25168     content : '',
25169     icon : '',
25170     footer : '',
25171     fhref : '',
25172     ficon : '',
25173     
25174     getAutoCreate : function(){
25175         
25176         var cfg = {
25177             tag : 'div',
25178             cls : 'small-box ',
25179             cn : [
25180                 {
25181                     tag : 'div',
25182                     cls : 'inner',
25183                     cn :[
25184                         {
25185                             tag : 'h3',
25186                             cls : 'roo-headline',
25187                             html : this.headline
25188                         },
25189                         {
25190                             tag : 'p',
25191                             cls : 'roo-content',
25192                             html : this.content
25193                         }
25194                     ]
25195                 }
25196             ]
25197         };
25198         
25199         if(this.icon){
25200             cfg.cn.push({
25201                 tag : 'div',
25202                 cls : 'icon',
25203                 cn :[
25204                     {
25205                         tag : 'i',
25206                         cls : 'ion ' + this.icon
25207                     }
25208                 ]
25209             });
25210         }
25211         
25212         if(this.footer){
25213             var footer = {
25214                 tag : 'a',
25215                 cls : 'small-box-footer',
25216                 href : this.fhref || '#',
25217                 html : this.footer
25218             };
25219             
25220             cfg.cn.push(footer);
25221             
25222         }
25223         
25224         return  cfg;
25225     },
25226
25227     onRender : function(ct,position){
25228         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25229
25230
25231        
25232                 
25233     },
25234
25235     setHeadline: function (value)
25236     {
25237         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25238     },
25239     
25240     setFooter: function (value, href)
25241     {
25242         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25243         
25244         if(href){
25245             this.el.select('a.small-box-footer',true).first().attr('href', href);
25246         }
25247         
25248     },
25249
25250     setContent: function (value)
25251     {
25252         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25253     },
25254
25255     initEvents: function() 
25256     {   
25257         
25258     }
25259     
25260 });
25261
25262  
25263 /*
25264  * - LGPL
25265  *
25266  * TabBox
25267  * 
25268  */
25269 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25270
25271 /**
25272  * @class Roo.bootstrap.dash.TabBox
25273  * @extends Roo.bootstrap.Component
25274  * Bootstrap TabBox class
25275  * @cfg {String} title Title of the TabBox
25276  * @cfg {String} icon Icon of the TabBox
25277  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25278  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25279  * 
25280  * @constructor
25281  * Create a new TabBox
25282  * @param {Object} config The config object
25283  */
25284
25285
25286 Roo.bootstrap.dash.TabBox = function(config){
25287     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25288     this.addEvents({
25289         // raw events
25290         /**
25291          * @event addpane
25292          * When a pane is added
25293          * @param {Roo.bootstrap.dash.TabPane} pane
25294          */
25295         "addpane" : true,
25296         /**
25297          * @event activatepane
25298          * When a pane is activated
25299          * @param {Roo.bootstrap.dash.TabPane} pane
25300          */
25301         "activatepane" : true
25302         
25303          
25304     });
25305     
25306     this.panes = [];
25307 };
25308
25309 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25310
25311     title : '',
25312     icon : false,
25313     showtabs : true,
25314     tabScrollable : false,
25315     
25316     getChildContainer : function()
25317     {
25318         return this.el.select('.tab-content', true).first();
25319     },
25320     
25321     getAutoCreate : function(){
25322         
25323         var header = {
25324             tag: 'li',
25325             cls: 'pull-left header',
25326             html: this.title,
25327             cn : []
25328         };
25329         
25330         if(this.icon){
25331             header.cn.push({
25332                 tag: 'i',
25333                 cls: 'fa ' + this.icon
25334             });
25335         }
25336         
25337         var h = {
25338             tag: 'ul',
25339             cls: 'nav nav-tabs pull-right',
25340             cn: [
25341                 header
25342             ]
25343         };
25344         
25345         if(this.tabScrollable){
25346             h = {
25347                 tag: 'div',
25348                 cls: 'tab-header',
25349                 cn: [
25350                     {
25351                         tag: 'ul',
25352                         cls: 'nav nav-tabs pull-right',
25353                         cn: [
25354                             header
25355                         ]
25356                     }
25357                 ]
25358             };
25359         }
25360         
25361         var cfg = {
25362             tag: 'div',
25363             cls: 'nav-tabs-custom',
25364             cn: [
25365                 h,
25366                 {
25367                     tag: 'div',
25368                     cls: 'tab-content no-padding',
25369                     cn: []
25370                 }
25371             ]
25372         };
25373
25374         return  cfg;
25375     },
25376     initEvents : function()
25377     {
25378         //Roo.log('add add pane handler');
25379         this.on('addpane', this.onAddPane, this);
25380     },
25381      /**
25382      * Updates the box title
25383      * @param {String} html to set the title to.
25384      */
25385     setTitle : function(value)
25386     {
25387         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25388     },
25389     onAddPane : function(pane)
25390     {
25391         this.panes.push(pane);
25392         //Roo.log('addpane');
25393         //Roo.log(pane);
25394         // tabs are rendere left to right..
25395         if(!this.showtabs){
25396             return;
25397         }
25398         
25399         var ctr = this.el.select('.nav-tabs', true).first();
25400          
25401          
25402         var existing = ctr.select('.nav-tab',true);
25403         var qty = existing.getCount();;
25404         
25405         
25406         var tab = ctr.createChild({
25407             tag : 'li',
25408             cls : 'nav-tab' + (qty ? '' : ' active'),
25409             cn : [
25410                 {
25411                     tag : 'a',
25412                     href:'#',
25413                     html : pane.title
25414                 }
25415             ]
25416         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25417         pane.tab = tab;
25418         
25419         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25420         if (!qty) {
25421             pane.el.addClass('active');
25422         }
25423         
25424                 
25425     },
25426     onTabClick : function(ev,un,ob,pane)
25427     {
25428         //Roo.log('tab - prev default');
25429         ev.preventDefault();
25430         
25431         
25432         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25433         pane.tab.addClass('active');
25434         //Roo.log(pane.title);
25435         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25436         // technically we should have a deactivate event.. but maybe add later.
25437         // and it should not de-activate the selected tab...
25438         this.fireEvent('activatepane', pane);
25439         pane.el.addClass('active');
25440         pane.fireEvent('activate');
25441         
25442         
25443     },
25444     
25445     getActivePane : function()
25446     {
25447         var r = false;
25448         Roo.each(this.panes, function(p) {
25449             if(p.el.hasClass('active')){
25450                 r = p;
25451                 return false;
25452             }
25453             
25454             return;
25455         });
25456         
25457         return r;
25458     }
25459     
25460     
25461 });
25462
25463  
25464 /*
25465  * - LGPL
25466  *
25467  * Tab pane
25468  * 
25469  */
25470 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25471 /**
25472  * @class Roo.bootstrap.TabPane
25473  * @extends Roo.bootstrap.Component
25474  * Bootstrap TabPane class
25475  * @cfg {Boolean} active (false | true) Default false
25476  * @cfg {String} title title of panel
25477
25478  * 
25479  * @constructor
25480  * Create a new TabPane
25481  * @param {Object} config The config object
25482  */
25483
25484 Roo.bootstrap.dash.TabPane = function(config){
25485     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25486     
25487     this.addEvents({
25488         // raw events
25489         /**
25490          * @event activate
25491          * When a pane is activated
25492          * @param {Roo.bootstrap.dash.TabPane} pane
25493          */
25494         "activate" : true
25495          
25496     });
25497 };
25498
25499 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25500     
25501     active : false,
25502     title : '',
25503     
25504     // the tabBox that this is attached to.
25505     tab : false,
25506      
25507     getAutoCreate : function() 
25508     {
25509         var cfg = {
25510             tag: 'div',
25511             cls: 'tab-pane'
25512         };
25513         
25514         if(this.active){
25515             cfg.cls += ' active';
25516         }
25517         
25518         return cfg;
25519     },
25520     initEvents  : function()
25521     {
25522         //Roo.log('trigger add pane handler');
25523         this.parent().fireEvent('addpane', this)
25524     },
25525     
25526      /**
25527      * Updates the tab title 
25528      * @param {String} html to set the title to.
25529      */
25530     setTitle: function(str)
25531     {
25532         if (!this.tab) {
25533             return;
25534         }
25535         this.title = str;
25536         this.tab.select('a', true).first().dom.innerHTML = str;
25537         
25538     }
25539     
25540     
25541     
25542 });
25543
25544  
25545
25546
25547  /*
25548  * - LGPL
25549  *
25550  * menu
25551  * 
25552  */
25553 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25554
25555 /**
25556  * @class Roo.bootstrap.menu.Menu
25557  * @extends Roo.bootstrap.Component
25558  * Bootstrap Menu class - container for Menu
25559  * @cfg {String} html Text of the menu
25560  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25561  * @cfg {String} icon Font awesome icon
25562  * @cfg {String} pos Menu align to (top | bottom) default bottom
25563  * 
25564  * 
25565  * @constructor
25566  * Create a new Menu
25567  * @param {Object} config The config object
25568  */
25569
25570
25571 Roo.bootstrap.menu.Menu = function(config){
25572     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25573     
25574     this.addEvents({
25575         /**
25576          * @event beforeshow
25577          * Fires before this menu is displayed
25578          * @param {Roo.bootstrap.menu.Menu} this
25579          */
25580         beforeshow : true,
25581         /**
25582          * @event beforehide
25583          * Fires before this menu is hidden
25584          * @param {Roo.bootstrap.menu.Menu} this
25585          */
25586         beforehide : true,
25587         /**
25588          * @event show
25589          * Fires after this menu is displayed
25590          * @param {Roo.bootstrap.menu.Menu} this
25591          */
25592         show : true,
25593         /**
25594          * @event hide
25595          * Fires after this menu is hidden
25596          * @param {Roo.bootstrap.menu.Menu} this
25597          */
25598         hide : true,
25599         /**
25600          * @event click
25601          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25602          * @param {Roo.bootstrap.menu.Menu} this
25603          * @param {Roo.EventObject} e
25604          */
25605         click : true
25606     });
25607     
25608 };
25609
25610 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25611     
25612     submenu : false,
25613     html : '',
25614     weight : 'default',
25615     icon : false,
25616     pos : 'bottom',
25617     
25618     
25619     getChildContainer : function() {
25620         if(this.isSubMenu){
25621             return this.el;
25622         }
25623         
25624         return this.el.select('ul.dropdown-menu', true).first();  
25625     },
25626     
25627     getAutoCreate : function()
25628     {
25629         var text = [
25630             {
25631                 tag : 'span',
25632                 cls : 'roo-menu-text',
25633                 html : this.html
25634             }
25635         ];
25636         
25637         if(this.icon){
25638             text.unshift({
25639                 tag : 'i',
25640                 cls : 'fa ' + this.icon
25641             })
25642         }
25643         
25644         
25645         var cfg = {
25646             tag : 'div',
25647             cls : 'btn-group',
25648             cn : [
25649                 {
25650                     tag : 'button',
25651                     cls : 'dropdown-button btn btn-' + this.weight,
25652                     cn : text
25653                 },
25654                 {
25655                     tag : 'button',
25656                     cls : 'dropdown-toggle btn btn-' + this.weight,
25657                     cn : [
25658                         {
25659                             tag : 'span',
25660                             cls : 'caret'
25661                         }
25662                     ]
25663                 },
25664                 {
25665                     tag : 'ul',
25666                     cls : 'dropdown-menu'
25667                 }
25668             ]
25669             
25670         };
25671         
25672         if(this.pos == 'top'){
25673             cfg.cls += ' dropup';
25674         }
25675         
25676         if(this.isSubMenu){
25677             cfg = {
25678                 tag : 'ul',
25679                 cls : 'dropdown-menu'
25680             }
25681         }
25682         
25683         return cfg;
25684     },
25685     
25686     onRender : function(ct, position)
25687     {
25688         this.isSubMenu = ct.hasClass('dropdown-submenu');
25689         
25690         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25691     },
25692     
25693     initEvents : function() 
25694     {
25695         if(this.isSubMenu){
25696             return;
25697         }
25698         
25699         this.hidden = true;
25700         
25701         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25702         this.triggerEl.on('click', this.onTriggerPress, this);
25703         
25704         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25705         this.buttonEl.on('click', this.onClick, this);
25706         
25707     },
25708     
25709     list : function()
25710     {
25711         if(this.isSubMenu){
25712             return this.el;
25713         }
25714         
25715         return this.el.select('ul.dropdown-menu', true).first();
25716     },
25717     
25718     onClick : function(e)
25719     {
25720         this.fireEvent("click", this, e);
25721     },
25722     
25723     onTriggerPress  : function(e)
25724     {   
25725         if (this.isVisible()) {
25726             this.hide();
25727         } else {
25728             this.show();
25729         }
25730     },
25731     
25732     isVisible : function(){
25733         return !this.hidden;
25734     },
25735     
25736     show : function()
25737     {
25738         this.fireEvent("beforeshow", this);
25739         
25740         this.hidden = false;
25741         this.el.addClass('open');
25742         
25743         Roo.get(document).on("mouseup", this.onMouseUp, this);
25744         
25745         this.fireEvent("show", this);
25746         
25747         
25748     },
25749     
25750     hide : function()
25751     {
25752         this.fireEvent("beforehide", this);
25753         
25754         this.hidden = true;
25755         this.el.removeClass('open');
25756         
25757         Roo.get(document).un("mouseup", this.onMouseUp);
25758         
25759         this.fireEvent("hide", this);
25760     },
25761     
25762     onMouseUp : function()
25763     {
25764         this.hide();
25765     }
25766     
25767 });
25768
25769  
25770  /*
25771  * - LGPL
25772  *
25773  * menu item
25774  * 
25775  */
25776 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25777
25778 /**
25779  * @class Roo.bootstrap.menu.Item
25780  * @extends Roo.bootstrap.Component
25781  * Bootstrap MenuItem class
25782  * @cfg {Boolean} submenu (true | false) default false
25783  * @cfg {String} html text of the item
25784  * @cfg {String} href the link
25785  * @cfg {Boolean} disable (true | false) default false
25786  * @cfg {Boolean} preventDefault (true | false) default true
25787  * @cfg {String} icon Font awesome icon
25788  * @cfg {String} pos Submenu align to (left | right) default right 
25789  * 
25790  * 
25791  * @constructor
25792  * Create a new Item
25793  * @param {Object} config The config object
25794  */
25795
25796
25797 Roo.bootstrap.menu.Item = function(config){
25798     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25799     this.addEvents({
25800         /**
25801          * @event mouseover
25802          * Fires when the mouse is hovering over this menu
25803          * @param {Roo.bootstrap.menu.Item} this
25804          * @param {Roo.EventObject} e
25805          */
25806         mouseover : true,
25807         /**
25808          * @event mouseout
25809          * Fires when the mouse exits this menu
25810          * @param {Roo.bootstrap.menu.Item} this
25811          * @param {Roo.EventObject} e
25812          */
25813         mouseout : true,
25814         // raw events
25815         /**
25816          * @event click
25817          * The raw click event for the entire grid.
25818          * @param {Roo.EventObject} e
25819          */
25820         click : true
25821     });
25822 };
25823
25824 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25825     
25826     submenu : false,
25827     href : '',
25828     html : '',
25829     preventDefault: true,
25830     disable : false,
25831     icon : false,
25832     pos : 'right',
25833     
25834     getAutoCreate : function()
25835     {
25836         var text = [
25837             {
25838                 tag : 'span',
25839                 cls : 'roo-menu-item-text',
25840                 html : this.html
25841             }
25842         ];
25843         
25844         if(this.icon){
25845             text.unshift({
25846                 tag : 'i',
25847                 cls : 'fa ' + this.icon
25848             })
25849         }
25850         
25851         var cfg = {
25852             tag : 'li',
25853             cn : [
25854                 {
25855                     tag : 'a',
25856                     href : this.href || '#',
25857                     cn : text
25858                 }
25859             ]
25860         };
25861         
25862         if(this.disable){
25863             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25864         }
25865         
25866         if(this.submenu){
25867             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25868             
25869             if(this.pos == 'left'){
25870                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25871             }
25872         }
25873         
25874         return cfg;
25875     },
25876     
25877     initEvents : function() 
25878     {
25879         this.el.on('mouseover', this.onMouseOver, this);
25880         this.el.on('mouseout', this.onMouseOut, this);
25881         
25882         this.el.select('a', true).first().on('click', this.onClick, this);
25883         
25884     },
25885     
25886     onClick : function(e)
25887     {
25888         if(this.preventDefault){
25889             e.preventDefault();
25890         }
25891         
25892         this.fireEvent("click", this, e);
25893     },
25894     
25895     onMouseOver : function(e)
25896     {
25897         if(this.submenu && this.pos == 'left'){
25898             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25899         }
25900         
25901         this.fireEvent("mouseover", this, e);
25902     },
25903     
25904     onMouseOut : function(e)
25905     {
25906         this.fireEvent("mouseout", this, e);
25907     }
25908 });
25909
25910  
25911
25912  /*
25913  * - LGPL
25914  *
25915  * menu separator
25916  * 
25917  */
25918 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25919
25920 /**
25921  * @class Roo.bootstrap.menu.Separator
25922  * @extends Roo.bootstrap.Component
25923  * Bootstrap Separator class
25924  * 
25925  * @constructor
25926  * Create a new Separator
25927  * @param {Object} config The config object
25928  */
25929
25930
25931 Roo.bootstrap.menu.Separator = function(config){
25932     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25933 };
25934
25935 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25936     
25937     getAutoCreate : function(){
25938         var cfg = {
25939             tag : 'li',
25940             cls: 'divider'
25941         };
25942         
25943         return cfg;
25944     }
25945    
25946 });
25947
25948  
25949
25950  /*
25951  * - LGPL
25952  *
25953  * Tooltip
25954  * 
25955  */
25956
25957 /**
25958  * @class Roo.bootstrap.Tooltip
25959  * Bootstrap Tooltip class
25960  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25961  * to determine which dom element triggers the tooltip.
25962  * 
25963  * It needs to add support for additional attributes like tooltip-position
25964  * 
25965  * @constructor
25966  * Create a new Toolti
25967  * @param {Object} config The config object
25968  */
25969
25970 Roo.bootstrap.Tooltip = function(config){
25971     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25972     
25973     this.alignment = Roo.bootstrap.Tooltip.alignment;
25974     
25975     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25976         this.alignment = config.alignment;
25977     }
25978     
25979 };
25980
25981 Roo.apply(Roo.bootstrap.Tooltip, {
25982     /**
25983      * @function init initialize tooltip monitoring.
25984      * @static
25985      */
25986     currentEl : false,
25987     currentTip : false,
25988     currentRegion : false,
25989     
25990     //  init : delay?
25991     
25992     init : function()
25993     {
25994         Roo.get(document).on('mouseover', this.enter ,this);
25995         Roo.get(document).on('mouseout', this.leave, this);
25996          
25997         
25998         this.currentTip = new Roo.bootstrap.Tooltip();
25999     },
26000     
26001     enter : function(ev)
26002     {
26003         var dom = ev.getTarget();
26004         
26005         //Roo.log(['enter',dom]);
26006         var el = Roo.fly(dom);
26007         if (this.currentEl) {
26008             //Roo.log(dom);
26009             //Roo.log(this.currentEl);
26010             //Roo.log(this.currentEl.contains(dom));
26011             if (this.currentEl == el) {
26012                 return;
26013             }
26014             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26015                 return;
26016             }
26017
26018         }
26019         
26020         if (this.currentTip.el) {
26021             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26022         }    
26023         //Roo.log(ev);
26024         
26025         if(!el || el.dom == document){
26026             return;
26027         }
26028         
26029         var bindEl = el;
26030         
26031         // you can not look for children, as if el is the body.. then everythign is the child..
26032         if (!el.attr('tooltip')) { //
26033             if (!el.select("[tooltip]").elements.length) {
26034                 return;
26035             }
26036             // is the mouse over this child...?
26037             bindEl = el.select("[tooltip]").first();
26038             var xy = ev.getXY();
26039             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26040                 //Roo.log("not in region.");
26041                 return;
26042             }
26043             //Roo.log("child element over..");
26044             
26045         }
26046         this.currentEl = bindEl;
26047         this.currentTip.bind(bindEl);
26048         this.currentRegion = Roo.lib.Region.getRegion(dom);
26049         this.currentTip.enter();
26050         
26051     },
26052     leave : function(ev)
26053     {
26054         var dom = ev.getTarget();
26055         //Roo.log(['leave',dom]);
26056         if (!this.currentEl) {
26057             return;
26058         }
26059         
26060         
26061         if (dom != this.currentEl.dom) {
26062             return;
26063         }
26064         var xy = ev.getXY();
26065         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
26066             return;
26067         }
26068         // only activate leave if mouse cursor is outside... bounding box..
26069         
26070         
26071         
26072         
26073         if (this.currentTip) {
26074             this.currentTip.leave();
26075         }
26076         //Roo.log('clear currentEl');
26077         this.currentEl = false;
26078         
26079         
26080     },
26081     alignment : {
26082         'left' : ['r-l', [-2,0], 'right'],
26083         'right' : ['l-r', [2,0], 'left'],
26084         'bottom' : ['t-b', [0,2], 'top'],
26085         'top' : [ 'b-t', [0,-2], 'bottom']
26086     }
26087     
26088 });
26089
26090
26091 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
26092     
26093     
26094     bindEl : false,
26095     
26096     delay : null, // can be { show : 300 , hide: 500}
26097     
26098     timeout : null,
26099     
26100     hoverState : null, //???
26101     
26102     placement : 'bottom', 
26103     
26104     alignment : false,
26105     
26106     getAutoCreate : function(){
26107     
26108         var cfg = {
26109            cls : 'tooltip',
26110            role : 'tooltip',
26111            cn : [
26112                 {
26113                     cls : 'tooltip-arrow'
26114                 },
26115                 {
26116                     cls : 'tooltip-inner'
26117                 }
26118            ]
26119         };
26120         
26121         return cfg;
26122     },
26123     bind : function(el)
26124     {
26125         this.bindEl = el;
26126     },
26127       
26128     
26129     enter : function () {
26130        
26131         if (this.timeout != null) {
26132             clearTimeout(this.timeout);
26133         }
26134         
26135         this.hoverState = 'in';
26136          //Roo.log("enter - show");
26137         if (!this.delay || !this.delay.show) {
26138             this.show();
26139             return;
26140         }
26141         var _t = this;
26142         this.timeout = setTimeout(function () {
26143             if (_t.hoverState == 'in') {
26144                 _t.show();
26145             }
26146         }, this.delay.show);
26147     },
26148     leave : function()
26149     {
26150         clearTimeout(this.timeout);
26151     
26152         this.hoverState = 'out';
26153          if (!this.delay || !this.delay.hide) {
26154             this.hide();
26155             return;
26156         }
26157        
26158         var _t = this;
26159         this.timeout = setTimeout(function () {
26160             //Roo.log("leave - timeout");
26161             
26162             if (_t.hoverState == 'out') {
26163                 _t.hide();
26164                 Roo.bootstrap.Tooltip.currentEl = false;
26165             }
26166         }, delay);
26167     },
26168     
26169     show : function (msg)
26170     {
26171         if (!this.el) {
26172             this.render(document.body);
26173         }
26174         // set content.
26175         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26176         
26177         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26178         
26179         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26180         
26181         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26182         
26183         var placement = typeof this.placement == 'function' ?
26184             this.placement.call(this, this.el, on_el) :
26185             this.placement;
26186             
26187         var autoToken = /\s?auto?\s?/i;
26188         var autoPlace = autoToken.test(placement);
26189         if (autoPlace) {
26190             placement = placement.replace(autoToken, '') || 'top';
26191         }
26192         
26193         //this.el.detach()
26194         //this.el.setXY([0,0]);
26195         this.el.show();
26196         //this.el.dom.style.display='block';
26197         
26198         //this.el.appendTo(on_el);
26199         
26200         var p = this.getPosition();
26201         var box = this.el.getBox();
26202         
26203         if (autoPlace) {
26204             // fixme..
26205         }
26206         
26207         var align = this.alignment[placement];
26208         
26209         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26210         
26211         if(placement == 'top' || placement == 'bottom'){
26212             if(xy[0] < 0){
26213                 placement = 'right';
26214             }
26215             
26216             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26217                 placement = 'left';
26218             }
26219             
26220             var scroll = Roo.select('body', true).first().getScroll();
26221             
26222             if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26223                 placement = 'top';
26224             }
26225             
26226         }
26227         
26228         this.el.alignTo(this.bindEl, align[0],align[1]);
26229         //var arrow = this.el.select('.arrow',true).first();
26230         //arrow.set(align[2], 
26231         
26232         this.el.addClass(placement);
26233         
26234         this.el.addClass('in fade');
26235         
26236         this.hoverState = null;
26237         
26238         if (this.el.hasClass('fade')) {
26239             // fade it?
26240         }
26241         
26242     },
26243     hide : function()
26244     {
26245          
26246         if (!this.el) {
26247             return;
26248         }
26249         //this.el.setXY([0,0]);
26250         this.el.removeClass('in');
26251         //this.el.hide();
26252         
26253     }
26254     
26255 });
26256  
26257
26258  /*
26259  * - LGPL
26260  *
26261  * Location Picker
26262  * 
26263  */
26264
26265 /**
26266  * @class Roo.bootstrap.LocationPicker
26267  * @extends Roo.bootstrap.Component
26268  * Bootstrap LocationPicker class
26269  * @cfg {Number} latitude Position when init default 0
26270  * @cfg {Number} longitude Position when init default 0
26271  * @cfg {Number} zoom default 15
26272  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26273  * @cfg {Boolean} mapTypeControl default false
26274  * @cfg {Boolean} disableDoubleClickZoom default false
26275  * @cfg {Boolean} scrollwheel default true
26276  * @cfg {Boolean} streetViewControl default false
26277  * @cfg {Number} radius default 0
26278  * @cfg {String} locationName
26279  * @cfg {Boolean} draggable default true
26280  * @cfg {Boolean} enableAutocomplete default false
26281  * @cfg {Boolean} enableReverseGeocode default true
26282  * @cfg {String} markerTitle
26283  * 
26284  * @constructor
26285  * Create a new LocationPicker
26286  * @param {Object} config The config object
26287  */
26288
26289
26290 Roo.bootstrap.LocationPicker = function(config){
26291     
26292     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26293     
26294     this.addEvents({
26295         /**
26296          * @event initial
26297          * Fires when the picker initialized.
26298          * @param {Roo.bootstrap.LocationPicker} this
26299          * @param {Google Location} location
26300          */
26301         initial : true,
26302         /**
26303          * @event positionchanged
26304          * Fires when the picker position changed.
26305          * @param {Roo.bootstrap.LocationPicker} this
26306          * @param {Google Location} location
26307          */
26308         positionchanged : true,
26309         /**
26310          * @event resize
26311          * Fires when the map resize.
26312          * @param {Roo.bootstrap.LocationPicker} this
26313          */
26314         resize : true,
26315         /**
26316          * @event show
26317          * Fires when the map show.
26318          * @param {Roo.bootstrap.LocationPicker} this
26319          */
26320         show : true,
26321         /**
26322          * @event hide
26323          * Fires when the map hide.
26324          * @param {Roo.bootstrap.LocationPicker} this
26325          */
26326         hide : true,
26327         /**
26328          * @event mapClick
26329          * Fires when click the map.
26330          * @param {Roo.bootstrap.LocationPicker} this
26331          * @param {Map event} e
26332          */
26333         mapClick : true,
26334         /**
26335          * @event mapRightClick
26336          * Fires when right click the map.
26337          * @param {Roo.bootstrap.LocationPicker} this
26338          * @param {Map event} e
26339          */
26340         mapRightClick : true,
26341         /**
26342          * @event markerClick
26343          * Fires when click the marker.
26344          * @param {Roo.bootstrap.LocationPicker} this
26345          * @param {Map event} e
26346          */
26347         markerClick : true,
26348         /**
26349          * @event markerRightClick
26350          * Fires when right click the marker.
26351          * @param {Roo.bootstrap.LocationPicker} this
26352          * @param {Map event} e
26353          */
26354         markerRightClick : true,
26355         /**
26356          * @event OverlayViewDraw
26357          * Fires when OverlayView Draw
26358          * @param {Roo.bootstrap.LocationPicker} this
26359          */
26360         OverlayViewDraw : true,
26361         /**
26362          * @event OverlayViewOnAdd
26363          * Fires when OverlayView Draw
26364          * @param {Roo.bootstrap.LocationPicker} this
26365          */
26366         OverlayViewOnAdd : true,
26367         /**
26368          * @event OverlayViewOnRemove
26369          * Fires when OverlayView Draw
26370          * @param {Roo.bootstrap.LocationPicker} this
26371          */
26372         OverlayViewOnRemove : true,
26373         /**
26374          * @event OverlayViewShow
26375          * Fires when OverlayView Draw
26376          * @param {Roo.bootstrap.LocationPicker} this
26377          * @param {Pixel} cpx
26378          */
26379         OverlayViewShow : true,
26380         /**
26381          * @event OverlayViewHide
26382          * Fires when OverlayView Draw
26383          * @param {Roo.bootstrap.LocationPicker} this
26384          */
26385         OverlayViewHide : true,
26386         /**
26387          * @event loadexception
26388          * Fires when load google lib failed.
26389          * @param {Roo.bootstrap.LocationPicker} this
26390          */
26391         loadexception : true
26392     });
26393         
26394 };
26395
26396 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26397     
26398     gMapContext: false,
26399     
26400     latitude: 0,
26401     longitude: 0,
26402     zoom: 15,
26403     mapTypeId: false,
26404     mapTypeControl: false,
26405     disableDoubleClickZoom: false,
26406     scrollwheel: true,
26407     streetViewControl: false,
26408     radius: 0,
26409     locationName: '',
26410     draggable: true,
26411     enableAutocomplete: false,
26412     enableReverseGeocode: true,
26413     markerTitle: '',
26414     
26415     getAutoCreate: function()
26416     {
26417
26418         var cfg = {
26419             tag: 'div',
26420             cls: 'roo-location-picker'
26421         };
26422         
26423         return cfg
26424     },
26425     
26426     initEvents: function(ct, position)
26427     {       
26428         if(!this.el.getWidth() || this.isApplied()){
26429             return;
26430         }
26431         
26432         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26433         
26434         this.initial();
26435     },
26436     
26437     initial: function()
26438     {
26439         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26440             this.fireEvent('loadexception', this);
26441             return;
26442         }
26443         
26444         if(!this.mapTypeId){
26445             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26446         }
26447         
26448         this.gMapContext = this.GMapContext();
26449         
26450         this.initOverlayView();
26451         
26452         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26453         
26454         var _this = this;
26455                 
26456         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26457             _this.setPosition(_this.gMapContext.marker.position);
26458         });
26459         
26460         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26461             _this.fireEvent('mapClick', this, event);
26462             
26463         });
26464
26465         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26466             _this.fireEvent('mapRightClick', this, event);
26467             
26468         });
26469         
26470         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26471             _this.fireEvent('markerClick', this, event);
26472             
26473         });
26474
26475         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26476             _this.fireEvent('markerRightClick', this, event);
26477             
26478         });
26479         
26480         this.setPosition(this.gMapContext.location);
26481         
26482         this.fireEvent('initial', this, this.gMapContext.location);
26483     },
26484     
26485     initOverlayView: function()
26486     {
26487         var _this = this;
26488         
26489         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26490             
26491             draw: function()
26492             {
26493                 _this.fireEvent('OverlayViewDraw', _this);
26494             },
26495             
26496             onAdd: function()
26497             {
26498                 _this.fireEvent('OverlayViewOnAdd', _this);
26499             },
26500             
26501             onRemove: function()
26502             {
26503                 _this.fireEvent('OverlayViewOnRemove', _this);
26504             },
26505             
26506             show: function(cpx)
26507             {
26508                 _this.fireEvent('OverlayViewShow', _this, cpx);
26509             },
26510             
26511             hide: function()
26512             {
26513                 _this.fireEvent('OverlayViewHide', _this);
26514             }
26515             
26516         });
26517     },
26518     
26519     fromLatLngToContainerPixel: function(event)
26520     {
26521         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26522     },
26523     
26524     isApplied: function() 
26525     {
26526         return this.getGmapContext() == false ? false : true;
26527     },
26528     
26529     getGmapContext: function() 
26530     {
26531         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26532     },
26533     
26534     GMapContext: function() 
26535     {
26536         var position = new google.maps.LatLng(this.latitude, this.longitude);
26537         
26538         var _map = new google.maps.Map(this.el.dom, {
26539             center: position,
26540             zoom: this.zoom,
26541             mapTypeId: this.mapTypeId,
26542             mapTypeControl: this.mapTypeControl,
26543             disableDoubleClickZoom: this.disableDoubleClickZoom,
26544             scrollwheel: this.scrollwheel,
26545             streetViewControl: this.streetViewControl,
26546             locationName: this.locationName,
26547             draggable: this.draggable,
26548             enableAutocomplete: this.enableAutocomplete,
26549             enableReverseGeocode: this.enableReverseGeocode
26550         });
26551         
26552         var _marker = new google.maps.Marker({
26553             position: position,
26554             map: _map,
26555             title: this.markerTitle,
26556             draggable: this.draggable
26557         });
26558         
26559         return {
26560             map: _map,
26561             marker: _marker,
26562             circle: null,
26563             location: position,
26564             radius: this.radius,
26565             locationName: this.locationName,
26566             addressComponents: {
26567                 formatted_address: null,
26568                 addressLine1: null,
26569                 addressLine2: null,
26570                 streetName: null,
26571                 streetNumber: null,
26572                 city: null,
26573                 district: null,
26574                 state: null,
26575                 stateOrProvince: null
26576             },
26577             settings: this,
26578             domContainer: this.el.dom,
26579             geodecoder: new google.maps.Geocoder()
26580         };
26581     },
26582     
26583     drawCircle: function(center, radius, options) 
26584     {
26585         if (this.gMapContext.circle != null) {
26586             this.gMapContext.circle.setMap(null);
26587         }
26588         if (radius > 0) {
26589             radius *= 1;
26590             options = Roo.apply({}, options, {
26591                 strokeColor: "#0000FF",
26592                 strokeOpacity: .35,
26593                 strokeWeight: 2,
26594                 fillColor: "#0000FF",
26595                 fillOpacity: .2
26596             });
26597             
26598             options.map = this.gMapContext.map;
26599             options.radius = radius;
26600             options.center = center;
26601             this.gMapContext.circle = new google.maps.Circle(options);
26602             return this.gMapContext.circle;
26603         }
26604         
26605         return null;
26606     },
26607     
26608     setPosition: function(location) 
26609     {
26610         this.gMapContext.location = location;
26611         this.gMapContext.marker.setPosition(location);
26612         this.gMapContext.map.panTo(location);
26613         this.drawCircle(location, this.gMapContext.radius, {});
26614         
26615         var _this = this;
26616         
26617         if (this.gMapContext.settings.enableReverseGeocode) {
26618             this.gMapContext.geodecoder.geocode({
26619                 latLng: this.gMapContext.location
26620             }, function(results, status) {
26621                 
26622                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26623                     _this.gMapContext.locationName = results[0].formatted_address;
26624                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26625                     
26626                     _this.fireEvent('positionchanged', this, location);
26627                 }
26628             });
26629             
26630             return;
26631         }
26632         
26633         this.fireEvent('positionchanged', this, location);
26634     },
26635     
26636     resize: function()
26637     {
26638         google.maps.event.trigger(this.gMapContext.map, "resize");
26639         
26640         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26641         
26642         this.fireEvent('resize', this);
26643     },
26644     
26645     setPositionByLatLng: function(latitude, longitude)
26646     {
26647         this.setPosition(new google.maps.LatLng(latitude, longitude));
26648     },
26649     
26650     getCurrentPosition: function() 
26651     {
26652         return {
26653             latitude: this.gMapContext.location.lat(),
26654             longitude: this.gMapContext.location.lng()
26655         };
26656     },
26657     
26658     getAddressName: function() 
26659     {
26660         return this.gMapContext.locationName;
26661     },
26662     
26663     getAddressComponents: function() 
26664     {
26665         return this.gMapContext.addressComponents;
26666     },
26667     
26668     address_component_from_google_geocode: function(address_components) 
26669     {
26670         var result = {};
26671         
26672         for (var i = 0; i < address_components.length; i++) {
26673             var component = address_components[i];
26674             if (component.types.indexOf("postal_code") >= 0) {
26675                 result.postalCode = component.short_name;
26676             } else if (component.types.indexOf("street_number") >= 0) {
26677                 result.streetNumber = component.short_name;
26678             } else if (component.types.indexOf("route") >= 0) {
26679                 result.streetName = component.short_name;
26680             } else if (component.types.indexOf("neighborhood") >= 0) {
26681                 result.city = component.short_name;
26682             } else if (component.types.indexOf("locality") >= 0) {
26683                 result.city = component.short_name;
26684             } else if (component.types.indexOf("sublocality") >= 0) {
26685                 result.district = component.short_name;
26686             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26687                 result.stateOrProvince = component.short_name;
26688             } else if (component.types.indexOf("country") >= 0) {
26689                 result.country = component.short_name;
26690             }
26691         }
26692         
26693         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26694         result.addressLine2 = "";
26695         return result;
26696     },
26697     
26698     setZoomLevel: function(zoom)
26699     {
26700         this.gMapContext.map.setZoom(zoom);
26701     },
26702     
26703     show: function()
26704     {
26705         if(!this.el){
26706             return;
26707         }
26708         
26709         this.el.show();
26710         
26711         this.resize();
26712         
26713         this.fireEvent('show', this);
26714     },
26715     
26716     hide: function()
26717     {
26718         if(!this.el){
26719             return;
26720         }
26721         
26722         this.el.hide();
26723         
26724         this.fireEvent('hide', this);
26725     }
26726     
26727 });
26728
26729 Roo.apply(Roo.bootstrap.LocationPicker, {
26730     
26731     OverlayView : function(map, options)
26732     {
26733         options = options || {};
26734         
26735         this.setMap(map);
26736     }
26737     
26738     
26739 });/*
26740  * - LGPL
26741  *
26742  * Alert
26743  * 
26744  */
26745
26746 /**
26747  * @class Roo.bootstrap.Alert
26748  * @extends Roo.bootstrap.Component
26749  * Bootstrap Alert class
26750  * @cfg {String} title The title of alert
26751  * @cfg {String} html The content of alert
26752  * @cfg {String} weight (  success | info | warning | danger )
26753  * @cfg {String} faicon font-awesomeicon
26754  * 
26755  * @constructor
26756  * Create a new alert
26757  * @param {Object} config The config object
26758  */
26759
26760
26761 Roo.bootstrap.Alert = function(config){
26762     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26763     
26764 };
26765
26766 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26767     
26768     title: '',
26769     html: '',
26770     weight: false,
26771     faicon: false,
26772     
26773     getAutoCreate : function()
26774     {
26775         
26776         var cfg = {
26777             tag : 'div',
26778             cls : 'alert',
26779             cn : [
26780                 {
26781                     tag : 'i',
26782                     cls : 'roo-alert-icon'
26783                     
26784                 },
26785                 {
26786                     tag : 'b',
26787                     cls : 'roo-alert-title',
26788                     html : this.title
26789                 },
26790                 {
26791                     tag : 'span',
26792                     cls : 'roo-alert-text',
26793                     html : this.html
26794                 }
26795             ]
26796         };
26797         
26798         if(this.faicon){
26799             cfg.cn[0].cls += ' fa ' + this.faicon;
26800         }
26801         
26802         if(this.weight){
26803             cfg.cls += ' alert-' + this.weight;
26804         }
26805         
26806         return cfg;
26807     },
26808     
26809     initEvents: function() 
26810     {
26811         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26812     },
26813     
26814     setTitle : function(str)
26815     {
26816         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26817     },
26818     
26819     setText : function(str)
26820     {
26821         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26822     },
26823     
26824     setWeight : function(weight)
26825     {
26826         if(this.weight){
26827             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26828         }
26829         
26830         this.weight = weight;
26831         
26832         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26833     },
26834     
26835     setIcon : function(icon)
26836     {
26837         if(this.faicon){
26838             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26839         }
26840         
26841         this.faicon = icon;
26842         
26843         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26844     },
26845     
26846     hide: function() 
26847     {
26848         this.el.hide();   
26849     },
26850     
26851     show: function() 
26852     {  
26853         this.el.show();   
26854     }
26855     
26856 });
26857
26858  
26859 /*
26860 * Licence: LGPL
26861 */
26862
26863 /**
26864  * @class Roo.bootstrap.UploadCropbox
26865  * @extends Roo.bootstrap.Component
26866  * Bootstrap UploadCropbox class
26867  * @cfg {String} emptyText show when image has been loaded
26868  * @cfg {String} rotateNotify show when image too small to rotate
26869  * @cfg {Number} errorTimeout default 3000
26870  * @cfg {Number} minWidth default 300
26871  * @cfg {Number} minHeight default 300
26872  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26873  * @cfg {Boolean} isDocument (true|false) default false
26874  * @cfg {String} url action url
26875  * @cfg {String} paramName default 'imageUpload'
26876  * @cfg {String} method default POST
26877  * @cfg {Boolean} loadMask (true|false) default true
26878  * @cfg {Boolean} loadingText default 'Loading...'
26879  * 
26880  * @constructor
26881  * Create a new UploadCropbox
26882  * @param {Object} config The config object
26883  */
26884
26885 Roo.bootstrap.UploadCropbox = function(config){
26886     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26887     
26888     this.addEvents({
26889         /**
26890          * @event beforeselectfile
26891          * Fire before select file
26892          * @param {Roo.bootstrap.UploadCropbox} this
26893          */
26894         "beforeselectfile" : true,
26895         /**
26896          * @event initial
26897          * Fire after initEvent
26898          * @param {Roo.bootstrap.UploadCropbox} this
26899          */
26900         "initial" : true,
26901         /**
26902          * @event crop
26903          * Fire after initEvent
26904          * @param {Roo.bootstrap.UploadCropbox} this
26905          * @param {String} data
26906          */
26907         "crop" : true,
26908         /**
26909          * @event prepare
26910          * Fire when preparing the file data
26911          * @param {Roo.bootstrap.UploadCropbox} this
26912          * @param {Object} file
26913          */
26914         "prepare" : true,
26915         /**
26916          * @event exception
26917          * Fire when get exception
26918          * @param {Roo.bootstrap.UploadCropbox} this
26919          * @param {XMLHttpRequest} xhr
26920          */
26921         "exception" : true,
26922         /**
26923          * @event beforeloadcanvas
26924          * Fire before load the canvas
26925          * @param {Roo.bootstrap.UploadCropbox} this
26926          * @param {String} src
26927          */
26928         "beforeloadcanvas" : true,
26929         /**
26930          * @event trash
26931          * Fire when trash image
26932          * @param {Roo.bootstrap.UploadCropbox} this
26933          */
26934         "trash" : true,
26935         /**
26936          * @event download
26937          * Fire when download the image
26938          * @param {Roo.bootstrap.UploadCropbox} this
26939          */
26940         "download" : true,
26941         /**
26942          * @event footerbuttonclick
26943          * Fire when footerbuttonclick
26944          * @param {Roo.bootstrap.UploadCropbox} this
26945          * @param {String} type
26946          */
26947         "footerbuttonclick" : true,
26948         /**
26949          * @event resize
26950          * Fire when resize
26951          * @param {Roo.bootstrap.UploadCropbox} this
26952          */
26953         "resize" : true,
26954         /**
26955          * @event rotate
26956          * Fire when rotate the image
26957          * @param {Roo.bootstrap.UploadCropbox} this
26958          * @param {String} pos
26959          */
26960         "rotate" : true,
26961         /**
26962          * @event inspect
26963          * Fire when inspect the file
26964          * @param {Roo.bootstrap.UploadCropbox} this
26965          * @param {Object} file
26966          */
26967         "inspect" : true,
26968         /**
26969          * @event upload
26970          * Fire when xhr upload the file
26971          * @param {Roo.bootstrap.UploadCropbox} this
26972          * @param {Object} data
26973          */
26974         "upload" : true,
26975         /**
26976          * @event arrange
26977          * Fire when arrange the file data
26978          * @param {Roo.bootstrap.UploadCropbox} this
26979          * @param {Object} formData
26980          */
26981         "arrange" : true
26982     });
26983     
26984     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26985 };
26986
26987 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26988     
26989     emptyText : 'Click to upload image',
26990     rotateNotify : 'Image is too small to rotate',
26991     errorTimeout : 3000,
26992     scale : 0,
26993     baseScale : 1,
26994     rotate : 0,
26995     dragable : false,
26996     pinching : false,
26997     mouseX : 0,
26998     mouseY : 0,
26999     cropData : false,
27000     minWidth : 300,
27001     minHeight : 300,
27002     file : false,
27003     exif : {},
27004     baseRotate : 1,
27005     cropType : 'image/jpeg',
27006     buttons : false,
27007     canvasLoaded : false,
27008     isDocument : false,
27009     method : 'POST',
27010     paramName : 'imageUpload',
27011     loadMask : true,
27012     loadingText : 'Loading...',
27013     maskEl : false,
27014     
27015     getAutoCreate : function()
27016     {
27017         var cfg = {
27018             tag : 'div',
27019             cls : 'roo-upload-cropbox',
27020             cn : [
27021                 {
27022                     tag : 'input',
27023                     cls : 'roo-upload-cropbox-selector',
27024                     type : 'file'
27025                 },
27026                 {
27027                     tag : 'div',
27028                     cls : 'roo-upload-cropbox-body',
27029                     style : 'cursor:pointer',
27030                     cn : [
27031                         {
27032                             tag : 'div',
27033                             cls : 'roo-upload-cropbox-preview'
27034                         },
27035                         {
27036                             tag : 'div',
27037                             cls : 'roo-upload-cropbox-thumb'
27038                         },
27039                         {
27040                             tag : 'div',
27041                             cls : 'roo-upload-cropbox-empty-notify',
27042                             html : this.emptyText
27043                         },
27044                         {
27045                             tag : 'div',
27046                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27047                             html : this.rotateNotify
27048                         }
27049                     ]
27050                 },
27051                 {
27052                     tag : 'div',
27053                     cls : 'roo-upload-cropbox-footer',
27054                     cn : {
27055                         tag : 'div',
27056                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27057                         cn : []
27058                     }
27059                 }
27060             ]
27061         };
27062         
27063         return cfg;
27064     },
27065     
27066     onRender : function(ct, position)
27067     {
27068         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27069         
27070         if (this.buttons.length) {
27071             
27072             Roo.each(this.buttons, function(bb) {
27073                 
27074                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27075                 
27076                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27077                 
27078             }, this);
27079         }
27080         
27081         if(this.loadMask){
27082             this.maskEl = this.el;
27083         }
27084     },
27085     
27086     initEvents : function()
27087     {
27088         this.urlAPI = (window.createObjectURL && window) || 
27089                                 (window.URL && URL.revokeObjectURL && URL) || 
27090                                 (window.webkitURL && webkitURL);
27091                         
27092         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27093         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27094         
27095         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27096         this.selectorEl.hide();
27097         
27098         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27099         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27100         
27101         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27102         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27103         this.thumbEl.hide();
27104         
27105         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27106         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27107         
27108         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27109         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27110         this.errorEl.hide();
27111         
27112         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27113         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27114         this.footerEl.hide();
27115         
27116         this.setThumbBoxSize();
27117         
27118         this.bind();
27119         
27120         this.resize();
27121         
27122         this.fireEvent('initial', this);
27123     },
27124
27125     bind : function()
27126     {
27127         var _this = this;
27128         
27129         window.addEventListener("resize", function() { _this.resize(); } );
27130         
27131         this.bodyEl.on('click', this.beforeSelectFile, this);
27132         
27133         if(Roo.isTouch){
27134             this.bodyEl.on('touchstart', this.onTouchStart, this);
27135             this.bodyEl.on('touchmove', this.onTouchMove, this);
27136             this.bodyEl.on('touchend', this.onTouchEnd, this);
27137         }
27138         
27139         if(!Roo.isTouch){
27140             this.bodyEl.on('mousedown', this.onMouseDown, this);
27141             this.bodyEl.on('mousemove', this.onMouseMove, this);
27142             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27143             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27144             Roo.get(document).on('mouseup', this.onMouseUp, this);
27145         }
27146         
27147         this.selectorEl.on('change', this.onFileSelected, this);
27148     },
27149     
27150     reset : function()
27151     {    
27152         this.scale = 0;
27153         this.baseScale = 1;
27154         this.rotate = 0;
27155         this.baseRotate = 1;
27156         this.dragable = false;
27157         this.pinching = false;
27158         this.mouseX = 0;
27159         this.mouseY = 0;
27160         this.cropData = false;
27161         this.notifyEl.dom.innerHTML = this.emptyText;
27162         
27163         this.selectorEl.dom.value = '';
27164         
27165     },
27166     
27167     resize : function()
27168     {
27169         if(this.fireEvent('resize', this) != false){
27170             this.setThumbBoxPosition();
27171             this.setCanvasPosition();
27172         }
27173     },
27174     
27175     onFooterButtonClick : function(e, el, o, type)
27176     {
27177         switch (type) {
27178             case 'rotate-left' :
27179                 this.onRotateLeft(e);
27180                 break;
27181             case 'rotate-right' :
27182                 this.onRotateRight(e);
27183                 break;
27184             case 'picture' :
27185                 this.beforeSelectFile(e);
27186                 break;
27187             case 'trash' :
27188                 this.trash(e);
27189                 break;
27190             case 'crop' :
27191                 this.crop(e);
27192                 break;
27193             case 'download' :
27194                 this.download(e);
27195                 break;
27196             default :
27197                 break;
27198         }
27199         
27200         this.fireEvent('footerbuttonclick', this, type);
27201     },
27202     
27203     beforeSelectFile : function(e)
27204     {
27205         e.preventDefault();
27206         
27207         if(this.fireEvent('beforeselectfile', this) != false){
27208             this.selectorEl.dom.click();
27209         }
27210     },
27211     
27212     onFileSelected : function(e)
27213     {
27214         e.preventDefault();
27215         
27216         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27217             return;
27218         }
27219         
27220         var file = this.selectorEl.dom.files[0];
27221         
27222         if(this.fireEvent('inspect', this, file) != false){
27223             this.prepare(file);
27224         }
27225         
27226     },
27227     
27228     trash : function(e)
27229     {
27230         this.fireEvent('trash', this);
27231     },
27232     
27233     download : function(e)
27234     {
27235         this.fireEvent('download', this);
27236     },
27237     
27238     loadCanvas : function(src)
27239     {   
27240         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27241             
27242             this.reset();
27243             
27244             this.imageEl = document.createElement('img');
27245             
27246             var _this = this;
27247             
27248             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27249             
27250             this.imageEl.src = src;
27251         }
27252     },
27253     
27254     onLoadCanvas : function()
27255     {   
27256         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27257         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27258         
27259         this.bodyEl.un('click', this.beforeSelectFile, this);
27260         
27261         this.notifyEl.hide();
27262         this.thumbEl.show();
27263         this.footerEl.show();
27264         
27265         this.baseRotateLevel();
27266         
27267         if(this.isDocument){
27268             this.setThumbBoxSize();
27269         }
27270         
27271         this.setThumbBoxPosition();
27272         
27273         this.baseScaleLevel();
27274         
27275         this.draw();
27276         
27277         this.resize();
27278         
27279         this.canvasLoaded = true;
27280         
27281         if(this.loadMask){
27282             this.maskEl.unmask();
27283         }
27284         
27285     },
27286     
27287     setCanvasPosition : function()
27288     {   
27289         if(!this.canvasEl){
27290             return;
27291         }
27292         
27293         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27294         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27295         
27296         this.previewEl.setLeft(pw);
27297         this.previewEl.setTop(ph);
27298         
27299     },
27300     
27301     onMouseDown : function(e)
27302     {   
27303         e.stopEvent();
27304         
27305         this.dragable = true;
27306         this.pinching = false;
27307         
27308         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27309             this.dragable = false;
27310             return;
27311         }
27312         
27313         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27314         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27315         
27316     },
27317     
27318     onMouseMove : function(e)
27319     {   
27320         e.stopEvent();
27321         
27322         if(!this.canvasLoaded){
27323             return;
27324         }
27325         
27326         if (!this.dragable){
27327             return;
27328         }
27329         
27330         var minX = Math.ceil(this.thumbEl.getLeft(true));
27331         var minY = Math.ceil(this.thumbEl.getTop(true));
27332         
27333         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27334         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27335         
27336         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27337         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27338         
27339         x = x - this.mouseX;
27340         y = y - this.mouseY;
27341         
27342         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27343         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27344         
27345         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27346         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27347         
27348         this.previewEl.setLeft(bgX);
27349         this.previewEl.setTop(bgY);
27350         
27351         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27352         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27353     },
27354     
27355     onMouseUp : function(e)
27356     {   
27357         e.stopEvent();
27358         
27359         this.dragable = false;
27360     },
27361     
27362     onMouseWheel : function(e)
27363     {   
27364         e.stopEvent();
27365         
27366         this.startScale = this.scale;
27367         
27368         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27369         
27370         if(!this.zoomable()){
27371             this.scale = this.startScale;
27372             return;
27373         }
27374         
27375         this.draw();
27376         
27377         return;
27378     },
27379     
27380     zoomable : function()
27381     {
27382         var minScale = this.thumbEl.getWidth() / this.minWidth;
27383         
27384         if(this.minWidth < this.minHeight){
27385             minScale = this.thumbEl.getHeight() / this.minHeight;
27386         }
27387         
27388         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27389         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27390         
27391         if(
27392                 this.isDocument &&
27393                 (this.rotate == 0 || this.rotate == 180) && 
27394                 (
27395                     width > this.imageEl.OriginWidth || 
27396                     height > this.imageEl.OriginHeight ||
27397                     (width < this.minWidth && height < this.minHeight)
27398                 )
27399         ){
27400             return false;
27401         }
27402         
27403         if(
27404                 this.isDocument &&
27405                 (this.rotate == 90 || this.rotate == 270) && 
27406                 (
27407                     width > this.imageEl.OriginWidth || 
27408                     height > this.imageEl.OriginHeight ||
27409                     (width < this.minHeight && height < this.minWidth)
27410                 )
27411         ){
27412             return false;
27413         }
27414         
27415         if(
27416                 !this.isDocument &&
27417                 (this.rotate == 0 || this.rotate == 180) && 
27418                 (
27419                     width < this.minWidth || 
27420                     width > this.imageEl.OriginWidth || 
27421                     height < this.minHeight || 
27422                     height > this.imageEl.OriginHeight
27423                 )
27424         ){
27425             return false;
27426         }
27427         
27428         if(
27429                 !this.isDocument &&
27430                 (this.rotate == 90 || this.rotate == 270) && 
27431                 (
27432                     width < this.minHeight || 
27433                     width > this.imageEl.OriginWidth || 
27434                     height < this.minWidth || 
27435                     height > this.imageEl.OriginHeight
27436                 )
27437         ){
27438             return false;
27439         }
27440         
27441         return true;
27442         
27443     },
27444     
27445     onRotateLeft : function(e)
27446     {   
27447         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27448             
27449             var minScale = this.thumbEl.getWidth() / this.minWidth;
27450             
27451             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27452             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27453             
27454             this.startScale = this.scale;
27455             
27456             while (this.getScaleLevel() < minScale){
27457             
27458                 this.scale = this.scale + 1;
27459                 
27460                 if(!this.zoomable()){
27461                     break;
27462                 }
27463                 
27464                 if(
27465                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27466                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27467                 ){
27468                     continue;
27469                 }
27470                 
27471                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27472
27473                 this.draw();
27474                 
27475                 return;
27476             }
27477             
27478             this.scale = this.startScale;
27479             
27480             this.onRotateFail();
27481             
27482             return false;
27483         }
27484         
27485         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27486
27487         if(this.isDocument){
27488             this.setThumbBoxSize();
27489             this.setThumbBoxPosition();
27490             this.setCanvasPosition();
27491         }
27492         
27493         this.draw();
27494         
27495         this.fireEvent('rotate', this, 'left');
27496         
27497     },
27498     
27499     onRotateRight : function(e)
27500     {
27501         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27502             
27503             var minScale = this.thumbEl.getWidth() / this.minWidth;
27504         
27505             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27506             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27507             
27508             this.startScale = this.scale;
27509             
27510             while (this.getScaleLevel() < minScale){
27511             
27512                 this.scale = this.scale + 1;
27513                 
27514                 if(!this.zoomable()){
27515                     break;
27516                 }
27517                 
27518                 if(
27519                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27520                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27521                 ){
27522                     continue;
27523                 }
27524                 
27525                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27526
27527                 this.draw();
27528                 
27529                 return;
27530             }
27531             
27532             this.scale = this.startScale;
27533             
27534             this.onRotateFail();
27535             
27536             return false;
27537         }
27538         
27539         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27540
27541         if(this.isDocument){
27542             this.setThumbBoxSize();
27543             this.setThumbBoxPosition();
27544             this.setCanvasPosition();
27545         }
27546         
27547         this.draw();
27548         
27549         this.fireEvent('rotate', this, 'right');
27550     },
27551     
27552     onRotateFail : function()
27553     {
27554         this.errorEl.show(true);
27555         
27556         var _this = this;
27557         
27558         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27559     },
27560     
27561     draw : function()
27562     {
27563         this.previewEl.dom.innerHTML = '';
27564         
27565         var canvasEl = document.createElement("canvas");
27566         
27567         var contextEl = canvasEl.getContext("2d");
27568         
27569         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27570         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27571         var center = this.imageEl.OriginWidth / 2;
27572         
27573         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27574             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27575             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27576             center = this.imageEl.OriginHeight / 2;
27577         }
27578         
27579         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27580         
27581         contextEl.translate(center, center);
27582         contextEl.rotate(this.rotate * Math.PI / 180);
27583
27584         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27585         
27586         this.canvasEl = document.createElement("canvas");
27587         
27588         this.contextEl = this.canvasEl.getContext("2d");
27589         
27590         switch (this.rotate) {
27591             case 0 :
27592                 
27593                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27594                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27595                 
27596                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27597                 
27598                 break;
27599             case 90 : 
27600                 
27601                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27602                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27603                 
27604                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27605                     this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27606                     break;
27607                 }
27608                 
27609                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27610                 
27611                 break;
27612             case 180 :
27613                 
27614                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27615                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27616                 
27617                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27618                     this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27619                     break;
27620                 }
27621                 
27622                 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27623                 
27624                 break;
27625             case 270 :
27626                 
27627                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27628                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27629         
27630                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27631                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27632                     break;
27633                 }
27634                 
27635                 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27636                 
27637                 break;
27638             default : 
27639                 break;
27640         }
27641         
27642         this.previewEl.appendChild(this.canvasEl);
27643         
27644         this.setCanvasPosition();
27645     },
27646     
27647     crop : function()
27648     {
27649         if(!this.canvasLoaded){
27650             return;
27651         }
27652         
27653         var imageCanvas = document.createElement("canvas");
27654         
27655         var imageContext = imageCanvas.getContext("2d");
27656         
27657         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27658         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27659         
27660         var center = imageCanvas.width / 2;
27661         
27662         imageContext.translate(center, center);
27663         
27664         imageContext.rotate(this.rotate * Math.PI / 180);
27665         
27666         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27667         
27668         var canvas = document.createElement("canvas");
27669         
27670         var context = canvas.getContext("2d");
27671                 
27672         canvas.width = this.minWidth;
27673         canvas.height = this.minHeight;
27674
27675         switch (this.rotate) {
27676             case 0 :
27677                 
27678                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27679                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27680                 
27681                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27682                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27683                 
27684                 var targetWidth = this.minWidth - 2 * x;
27685                 var targetHeight = this.minHeight - 2 * y;
27686                 
27687                 var scale = 1;
27688                 
27689                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27690                     scale = targetWidth / width;
27691                 }
27692                 
27693                 if(x > 0 && y == 0){
27694                     scale = targetHeight / height;
27695                 }
27696                 
27697                 if(x > 0 && y > 0){
27698                     scale = targetWidth / width;
27699                     
27700                     if(width < height){
27701                         scale = targetHeight / height;
27702                     }
27703                 }
27704                 
27705                 context.scale(scale, scale);
27706                 
27707                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27708                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27709
27710                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27711                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27712
27713                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27714                 
27715                 break;
27716             case 90 : 
27717                 
27718                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27719                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27720                 
27721                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27722                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27723                 
27724                 var targetWidth = this.minWidth - 2 * x;
27725                 var targetHeight = this.minHeight - 2 * y;
27726                 
27727                 var scale = 1;
27728                 
27729                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27730                     scale = targetWidth / width;
27731                 }
27732                 
27733                 if(x > 0 && y == 0){
27734                     scale = targetHeight / height;
27735                 }
27736                 
27737                 if(x > 0 && y > 0){
27738                     scale = targetWidth / width;
27739                     
27740                     if(width < height){
27741                         scale = targetHeight / height;
27742                     }
27743                 }
27744                 
27745                 context.scale(scale, scale);
27746                 
27747                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27748                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27749
27750                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27751                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27752                 
27753                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27754                 
27755                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27756                 
27757                 break;
27758             case 180 :
27759                 
27760                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27761                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27762                 
27763                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27764                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27765                 
27766                 var targetWidth = this.minWidth - 2 * x;
27767                 var targetHeight = this.minHeight - 2 * y;
27768                 
27769                 var scale = 1;
27770                 
27771                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27772                     scale = targetWidth / width;
27773                 }
27774                 
27775                 if(x > 0 && y == 0){
27776                     scale = targetHeight / height;
27777                 }
27778                 
27779                 if(x > 0 && y > 0){
27780                     scale = targetWidth / width;
27781                     
27782                     if(width < height){
27783                         scale = targetHeight / height;
27784                     }
27785                 }
27786                 
27787                 context.scale(scale, scale);
27788                 
27789                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27790                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27791
27792                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27793                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27794
27795                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27796                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27797                 
27798                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27799                 
27800                 break;
27801             case 270 :
27802                 
27803                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27804                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27805                 
27806                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27807                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27808                 
27809                 var targetWidth = this.minWidth - 2 * x;
27810                 var targetHeight = this.minHeight - 2 * y;
27811                 
27812                 var scale = 1;
27813                 
27814                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27815                     scale = targetWidth / width;
27816                 }
27817                 
27818                 if(x > 0 && y == 0){
27819                     scale = targetHeight / height;
27820                 }
27821                 
27822                 if(x > 0 && y > 0){
27823                     scale = targetWidth / width;
27824                     
27825                     if(width < height){
27826                         scale = targetHeight / height;
27827                     }
27828                 }
27829                 
27830                 context.scale(scale, scale);
27831                 
27832                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27833                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27834
27835                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27836                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27837                 
27838                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27839                 
27840                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27841                 
27842                 break;
27843             default : 
27844                 break;
27845         }
27846         
27847         this.cropData = canvas.toDataURL(this.cropType);
27848         
27849         if(this.fireEvent('crop', this, this.cropData) !== false){
27850             this.process(this.file, this.cropData);
27851         }
27852         
27853         return;
27854         
27855     },
27856     
27857     setThumbBoxSize : function()
27858     {
27859         var width, height;
27860         
27861         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27862             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27863             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27864             
27865             this.minWidth = width;
27866             this.minHeight = height;
27867             
27868             if(this.rotate == 90 || this.rotate == 270){
27869                 this.minWidth = height;
27870                 this.minHeight = width;
27871             }
27872         }
27873         
27874         height = 300;
27875         width = Math.ceil(this.minWidth * height / this.minHeight);
27876         
27877         if(this.minWidth > this.minHeight){
27878             width = 300;
27879             height = Math.ceil(this.minHeight * width / this.minWidth);
27880         }
27881         
27882         this.thumbEl.setStyle({
27883             width : width + 'px',
27884             height : height + 'px'
27885         });
27886
27887         return;
27888             
27889     },
27890     
27891     setThumbBoxPosition : function()
27892     {
27893         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27894         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27895         
27896         this.thumbEl.setLeft(x);
27897         this.thumbEl.setTop(y);
27898         
27899     },
27900     
27901     baseRotateLevel : function()
27902     {
27903         this.baseRotate = 1;
27904         
27905         if(
27906                 typeof(this.exif) != 'undefined' &&
27907                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27908                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27909         ){
27910             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27911         }
27912         
27913         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27914         
27915     },
27916     
27917     baseScaleLevel : function()
27918     {
27919         var width, height;
27920         
27921         if(this.isDocument){
27922             
27923             if(this.baseRotate == 6 || this.baseRotate == 8){
27924             
27925                 height = this.thumbEl.getHeight();
27926                 this.baseScale = height / this.imageEl.OriginWidth;
27927
27928                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27929                     width = this.thumbEl.getWidth();
27930                     this.baseScale = width / this.imageEl.OriginHeight;
27931                 }
27932
27933                 return;
27934             }
27935
27936             height = this.thumbEl.getHeight();
27937             this.baseScale = height / this.imageEl.OriginHeight;
27938
27939             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27940                 width = this.thumbEl.getWidth();
27941                 this.baseScale = width / this.imageEl.OriginWidth;
27942             }
27943
27944             return;
27945         }
27946         
27947         if(this.baseRotate == 6 || this.baseRotate == 8){
27948             
27949             width = this.thumbEl.getHeight();
27950             this.baseScale = width / this.imageEl.OriginHeight;
27951             
27952             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27953                 height = this.thumbEl.getWidth();
27954                 this.baseScale = height / this.imageEl.OriginHeight;
27955             }
27956             
27957             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27958                 height = this.thumbEl.getWidth();
27959                 this.baseScale = height / this.imageEl.OriginHeight;
27960                 
27961                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27962                     width = this.thumbEl.getHeight();
27963                     this.baseScale = width / this.imageEl.OriginWidth;
27964                 }
27965             }
27966             
27967             return;
27968         }
27969         
27970         width = this.thumbEl.getWidth();
27971         this.baseScale = width / this.imageEl.OriginWidth;
27972         
27973         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27974             height = this.thumbEl.getHeight();
27975             this.baseScale = height / this.imageEl.OriginHeight;
27976         }
27977         
27978         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27979             
27980             height = this.thumbEl.getHeight();
27981             this.baseScale = height / this.imageEl.OriginHeight;
27982             
27983             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27984                 width = this.thumbEl.getWidth();
27985                 this.baseScale = width / this.imageEl.OriginWidth;
27986             }
27987             
27988         }
27989         
27990         return;
27991     },
27992     
27993     getScaleLevel : function()
27994     {
27995         return this.baseScale * Math.pow(1.1, this.scale);
27996     },
27997     
27998     onTouchStart : function(e)
27999     {
28000         if(!this.canvasLoaded){
28001             this.beforeSelectFile(e);
28002             return;
28003         }
28004         
28005         var touches = e.browserEvent.touches;
28006         
28007         if(!touches){
28008             return;
28009         }
28010         
28011         if(touches.length == 1){
28012             this.onMouseDown(e);
28013             return;
28014         }
28015         
28016         if(touches.length != 2){
28017             return;
28018         }
28019         
28020         var coords = [];
28021         
28022         for(var i = 0, finger; finger = touches[i]; i++){
28023             coords.push(finger.pageX, finger.pageY);
28024         }
28025         
28026         var x = Math.pow(coords[0] - coords[2], 2);
28027         var y = Math.pow(coords[1] - coords[3], 2);
28028         
28029         this.startDistance = Math.sqrt(x + y);
28030         
28031         this.startScale = this.scale;
28032         
28033         this.pinching = true;
28034         this.dragable = false;
28035         
28036     },
28037     
28038     onTouchMove : function(e)
28039     {
28040         if(!this.pinching && !this.dragable){
28041             return;
28042         }
28043         
28044         var touches = e.browserEvent.touches;
28045         
28046         if(!touches){
28047             return;
28048         }
28049         
28050         if(this.dragable){
28051             this.onMouseMove(e);
28052             return;
28053         }
28054         
28055         var coords = [];
28056         
28057         for(var i = 0, finger; finger = touches[i]; i++){
28058             coords.push(finger.pageX, finger.pageY);
28059         }
28060         
28061         var x = Math.pow(coords[0] - coords[2], 2);
28062         var y = Math.pow(coords[1] - coords[3], 2);
28063         
28064         this.endDistance = Math.sqrt(x + y);
28065         
28066         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28067         
28068         if(!this.zoomable()){
28069             this.scale = this.startScale;
28070             return;
28071         }
28072         
28073         this.draw();
28074         
28075     },
28076     
28077     onTouchEnd : function(e)
28078     {
28079         this.pinching = false;
28080         this.dragable = false;
28081         
28082     },
28083     
28084     process : function(file, crop)
28085     {
28086         if(this.loadMask){
28087             this.maskEl.mask(this.loadingText);
28088         }
28089         
28090         this.xhr = new XMLHttpRequest();
28091         
28092         file.xhr = this.xhr;
28093
28094         this.xhr.open(this.method, this.url, true);
28095         
28096         var headers = {
28097             "Accept": "application/json",
28098             "Cache-Control": "no-cache",
28099             "X-Requested-With": "XMLHttpRequest"
28100         };
28101         
28102         for (var headerName in headers) {
28103             var headerValue = headers[headerName];
28104             if (headerValue) {
28105                 this.xhr.setRequestHeader(headerName, headerValue);
28106             }
28107         }
28108         
28109         var _this = this;
28110         
28111         this.xhr.onload = function()
28112         {
28113             _this.xhrOnLoad(_this.xhr);
28114         }
28115         
28116         this.xhr.onerror = function()
28117         {
28118             _this.xhrOnError(_this.xhr);
28119         }
28120         
28121         var formData = new FormData();
28122
28123         formData.append('returnHTML', 'NO');
28124         
28125         if(crop){
28126             formData.append('crop', crop);
28127         }
28128         
28129         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28130             formData.append(this.paramName, file, file.name);
28131         }
28132         
28133         if(typeof(file.filename) != 'undefined'){
28134             formData.append('filename', file.filename);
28135         }
28136         
28137         if(typeof(file.mimetype) != 'undefined'){
28138             formData.append('mimetype', file.mimetype);
28139         }
28140         
28141         if(this.fireEvent('arrange', this, formData) != false){
28142             this.xhr.send(formData);
28143         };
28144     },
28145     
28146     xhrOnLoad : function(xhr)
28147     {
28148         if(this.loadMask){
28149             this.maskEl.unmask();
28150         }
28151         
28152         if (xhr.readyState !== 4) {
28153             this.fireEvent('exception', this, xhr);
28154             return;
28155         }
28156
28157         var response = Roo.decode(xhr.responseText);
28158         
28159         if(!response.success){
28160             this.fireEvent('exception', this, xhr);
28161             return;
28162         }
28163         
28164         var response = Roo.decode(xhr.responseText);
28165         
28166         this.fireEvent('upload', this, response);
28167         
28168     },
28169     
28170     xhrOnError : function()
28171     {
28172         if(this.loadMask){
28173             this.maskEl.unmask();
28174         }
28175         
28176         Roo.log('xhr on error');
28177         
28178         var response = Roo.decode(xhr.responseText);
28179           
28180         Roo.log(response);
28181         
28182     },
28183     
28184     prepare : function(file)
28185     {   
28186         if(this.loadMask){
28187             this.maskEl.mask(this.loadingText);
28188         }
28189         
28190         this.file = false;
28191         this.exif = {};
28192         
28193         if(typeof(file) === 'string'){
28194             this.loadCanvas(file);
28195             return;
28196         }
28197         
28198         if(!file || !this.urlAPI){
28199             return;
28200         }
28201         
28202         this.file = file;
28203         this.cropType = file.type;
28204         
28205         var _this = this;
28206         
28207         if(this.fireEvent('prepare', this, this.file) != false){
28208             
28209             var reader = new FileReader();
28210             
28211             reader.onload = function (e) {
28212                 if (e.target.error) {
28213                     Roo.log(e.target.error);
28214                     return;
28215                 }
28216                 
28217                 var buffer = e.target.result,
28218                     dataView = new DataView(buffer),
28219                     offset = 2,
28220                     maxOffset = dataView.byteLength - 4,
28221                     markerBytes,
28222                     markerLength;
28223                 
28224                 if (dataView.getUint16(0) === 0xffd8) {
28225                     while (offset < maxOffset) {
28226                         markerBytes = dataView.getUint16(offset);
28227                         
28228                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28229                             markerLength = dataView.getUint16(offset + 2) + 2;
28230                             if (offset + markerLength > dataView.byteLength) {
28231                                 Roo.log('Invalid meta data: Invalid segment size.');
28232                                 break;
28233                             }
28234                             
28235                             if(markerBytes == 0xffe1){
28236                                 _this.parseExifData(
28237                                     dataView,
28238                                     offset,
28239                                     markerLength
28240                                 );
28241                             }
28242                             
28243                             offset += markerLength;
28244                             
28245                             continue;
28246                         }
28247                         
28248                         break;
28249                     }
28250                     
28251                 }
28252                 
28253                 var url = _this.urlAPI.createObjectURL(_this.file);
28254                 
28255                 _this.loadCanvas(url);
28256                 
28257                 return;
28258             }
28259             
28260             reader.readAsArrayBuffer(this.file);
28261             
28262         }
28263         
28264     },
28265     
28266     parseExifData : function(dataView, offset, length)
28267     {
28268         var tiffOffset = offset + 10,
28269             littleEndian,
28270             dirOffset;
28271     
28272         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28273             // No Exif data, might be XMP data instead
28274             return;
28275         }
28276         
28277         // Check for the ASCII code for "Exif" (0x45786966):
28278         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28279             // No Exif data, might be XMP data instead
28280             return;
28281         }
28282         if (tiffOffset + 8 > dataView.byteLength) {
28283             Roo.log('Invalid Exif data: Invalid segment size.');
28284             return;
28285         }
28286         // Check for the two null bytes:
28287         if (dataView.getUint16(offset + 8) !== 0x0000) {
28288             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28289             return;
28290         }
28291         // Check the byte alignment:
28292         switch (dataView.getUint16(tiffOffset)) {
28293         case 0x4949:
28294             littleEndian = true;
28295             break;
28296         case 0x4D4D:
28297             littleEndian = false;
28298             break;
28299         default:
28300             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28301             return;
28302         }
28303         // Check for the TIFF tag marker (0x002A):
28304         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28305             Roo.log('Invalid Exif data: Missing TIFF marker.');
28306             return;
28307         }
28308         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28309         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28310         
28311         this.parseExifTags(
28312             dataView,
28313             tiffOffset,
28314             tiffOffset + dirOffset,
28315             littleEndian
28316         );
28317     },
28318     
28319     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28320     {
28321         var tagsNumber,
28322             dirEndOffset,
28323             i;
28324         if (dirOffset + 6 > dataView.byteLength) {
28325             Roo.log('Invalid Exif data: Invalid directory offset.');
28326             return;
28327         }
28328         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28329         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28330         if (dirEndOffset + 4 > dataView.byteLength) {
28331             Roo.log('Invalid Exif data: Invalid directory size.');
28332             return;
28333         }
28334         for (i = 0; i < tagsNumber; i += 1) {
28335             this.parseExifTag(
28336                 dataView,
28337                 tiffOffset,
28338                 dirOffset + 2 + 12 * i, // tag offset
28339                 littleEndian
28340             );
28341         }
28342         // Return the offset to the next directory:
28343         return dataView.getUint32(dirEndOffset, littleEndian);
28344     },
28345     
28346     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28347     {
28348         var tag = dataView.getUint16(offset, littleEndian);
28349         
28350         this.exif[tag] = this.getExifValue(
28351             dataView,
28352             tiffOffset,
28353             offset,
28354             dataView.getUint16(offset + 2, littleEndian), // tag type
28355             dataView.getUint32(offset + 4, littleEndian), // tag length
28356             littleEndian
28357         );
28358     },
28359     
28360     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28361     {
28362         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28363             tagSize,
28364             dataOffset,
28365             values,
28366             i,
28367             str,
28368             c;
28369     
28370         if (!tagType) {
28371             Roo.log('Invalid Exif data: Invalid tag type.');
28372             return;
28373         }
28374         
28375         tagSize = tagType.size * length;
28376         // Determine if the value is contained in the dataOffset bytes,
28377         // or if the value at the dataOffset is a pointer to the actual data:
28378         dataOffset = tagSize > 4 ?
28379                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28380         if (dataOffset + tagSize > dataView.byteLength) {
28381             Roo.log('Invalid Exif data: Invalid data offset.');
28382             return;
28383         }
28384         if (length === 1) {
28385             return tagType.getValue(dataView, dataOffset, littleEndian);
28386         }
28387         values = [];
28388         for (i = 0; i < length; i += 1) {
28389             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28390         }
28391         
28392         if (tagType.ascii) {
28393             str = '';
28394             // Concatenate the chars:
28395             for (i = 0; i < values.length; i += 1) {
28396                 c = values[i];
28397                 // Ignore the terminating NULL byte(s):
28398                 if (c === '\u0000') {
28399                     break;
28400                 }
28401                 str += c;
28402             }
28403             return str;
28404         }
28405         return values;
28406     }
28407     
28408 });
28409
28410 Roo.apply(Roo.bootstrap.UploadCropbox, {
28411     tags : {
28412         'Orientation': 0x0112
28413     },
28414     
28415     Orientation: {
28416             1: 0, //'top-left',
28417 //            2: 'top-right',
28418             3: 180, //'bottom-right',
28419 //            4: 'bottom-left',
28420 //            5: 'left-top',
28421             6: 90, //'right-top',
28422 //            7: 'right-bottom',
28423             8: 270 //'left-bottom'
28424     },
28425     
28426     exifTagTypes : {
28427         // byte, 8-bit unsigned int:
28428         1: {
28429             getValue: function (dataView, dataOffset) {
28430                 return dataView.getUint8(dataOffset);
28431             },
28432             size: 1
28433         },
28434         // ascii, 8-bit byte:
28435         2: {
28436             getValue: function (dataView, dataOffset) {
28437                 return String.fromCharCode(dataView.getUint8(dataOffset));
28438             },
28439             size: 1,
28440             ascii: true
28441         },
28442         // short, 16 bit int:
28443         3: {
28444             getValue: function (dataView, dataOffset, littleEndian) {
28445                 return dataView.getUint16(dataOffset, littleEndian);
28446             },
28447             size: 2
28448         },
28449         // long, 32 bit int:
28450         4: {
28451             getValue: function (dataView, dataOffset, littleEndian) {
28452                 return dataView.getUint32(dataOffset, littleEndian);
28453             },
28454             size: 4
28455         },
28456         // rational = two long values, first is numerator, second is denominator:
28457         5: {
28458             getValue: function (dataView, dataOffset, littleEndian) {
28459                 return dataView.getUint32(dataOffset, littleEndian) /
28460                     dataView.getUint32(dataOffset + 4, littleEndian);
28461             },
28462             size: 8
28463         },
28464         // slong, 32 bit signed int:
28465         9: {
28466             getValue: function (dataView, dataOffset, littleEndian) {
28467                 return dataView.getInt32(dataOffset, littleEndian);
28468             },
28469             size: 4
28470         },
28471         // srational, two slongs, first is numerator, second is denominator:
28472         10: {
28473             getValue: function (dataView, dataOffset, littleEndian) {
28474                 return dataView.getInt32(dataOffset, littleEndian) /
28475                     dataView.getInt32(dataOffset + 4, littleEndian);
28476             },
28477             size: 8
28478         }
28479     },
28480     
28481     footer : {
28482         STANDARD : [
28483             {
28484                 tag : 'div',
28485                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28486                 action : 'rotate-left',
28487                 cn : [
28488                     {
28489                         tag : 'button',
28490                         cls : 'btn btn-default',
28491                         html : '<i class="fa fa-undo"></i>'
28492                     }
28493                 ]
28494             },
28495             {
28496                 tag : 'div',
28497                 cls : 'btn-group roo-upload-cropbox-picture',
28498                 action : 'picture',
28499                 cn : [
28500                     {
28501                         tag : 'button',
28502                         cls : 'btn btn-default',
28503                         html : '<i class="fa fa-picture-o"></i>'
28504                     }
28505                 ]
28506             },
28507             {
28508                 tag : 'div',
28509                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28510                 action : 'rotate-right',
28511                 cn : [
28512                     {
28513                         tag : 'button',
28514                         cls : 'btn btn-default',
28515                         html : '<i class="fa fa-repeat"></i>'
28516                     }
28517                 ]
28518             }
28519         ],
28520         DOCUMENT : [
28521             {
28522                 tag : 'div',
28523                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28524                 action : 'rotate-left',
28525                 cn : [
28526                     {
28527                         tag : 'button',
28528                         cls : 'btn btn-default',
28529                         html : '<i class="fa fa-undo"></i>'
28530                     }
28531                 ]
28532             },
28533             {
28534                 tag : 'div',
28535                 cls : 'btn-group roo-upload-cropbox-download',
28536                 action : 'download',
28537                 cn : [
28538                     {
28539                         tag : 'button',
28540                         cls : 'btn btn-default',
28541                         html : '<i class="fa fa-download"></i>'
28542                     }
28543                 ]
28544             },
28545             {
28546                 tag : 'div',
28547                 cls : 'btn-group roo-upload-cropbox-crop',
28548                 action : 'crop',
28549                 cn : [
28550                     {
28551                         tag : 'button',
28552                         cls : 'btn btn-default',
28553                         html : '<i class="fa fa-crop"></i>'
28554                     }
28555                 ]
28556             },
28557             {
28558                 tag : 'div',
28559                 cls : 'btn-group roo-upload-cropbox-trash',
28560                 action : 'trash',
28561                 cn : [
28562                     {
28563                         tag : 'button',
28564                         cls : 'btn btn-default',
28565                         html : '<i class="fa fa-trash"></i>'
28566                     }
28567                 ]
28568             },
28569             {
28570                 tag : 'div',
28571                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28572                 action : 'rotate-right',
28573                 cn : [
28574                     {
28575                         tag : 'button',
28576                         cls : 'btn btn-default',
28577                         html : '<i class="fa fa-repeat"></i>'
28578                     }
28579                 ]
28580             }
28581         ],
28582         ROTATOR : [
28583             {
28584                 tag : 'div',
28585                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28586                 action : 'rotate-left',
28587                 cn : [
28588                     {
28589                         tag : 'button',
28590                         cls : 'btn btn-default',
28591                         html : '<i class="fa fa-undo"></i>'
28592                     }
28593                 ]
28594             },
28595             {
28596                 tag : 'div',
28597                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28598                 action : 'rotate-right',
28599                 cn : [
28600                     {
28601                         tag : 'button',
28602                         cls : 'btn btn-default',
28603                         html : '<i class="fa fa-repeat"></i>'
28604                     }
28605                 ]
28606             }
28607         ]
28608     }
28609 });
28610
28611 /*
28612 * Licence: LGPL
28613 */
28614
28615 /**
28616  * @class Roo.bootstrap.DocumentManager
28617  * @extends Roo.bootstrap.Component
28618  * Bootstrap DocumentManager class
28619  * @cfg {String} paramName default 'imageUpload'
28620  * @cfg {String} toolTipName default 'filename'
28621  * @cfg {String} method default POST
28622  * @cfg {String} url action url
28623  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28624  * @cfg {Boolean} multiple multiple upload default true
28625  * @cfg {Number} thumbSize default 300
28626  * @cfg {String} fieldLabel
28627  * @cfg {Number} labelWidth default 4
28628  * @cfg {String} labelAlign (left|top) default left
28629  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28630 * @cfg {Number} labellg set the width of label (1-12)
28631  * @cfg {Number} labelmd set the width of label (1-12)
28632  * @cfg {Number} labelsm set the width of label (1-12)
28633  * @cfg {Number} labelxs set the width of label (1-12)
28634  * 
28635  * @constructor
28636  * Create a new DocumentManager
28637  * @param {Object} config The config object
28638  */
28639
28640 Roo.bootstrap.DocumentManager = function(config){
28641     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28642     
28643     this.files = [];
28644     this.delegates = [];
28645     
28646     this.addEvents({
28647         /**
28648          * @event initial
28649          * Fire when initial the DocumentManager
28650          * @param {Roo.bootstrap.DocumentManager} this
28651          */
28652         "initial" : true,
28653         /**
28654          * @event inspect
28655          * inspect selected file
28656          * @param {Roo.bootstrap.DocumentManager} this
28657          * @param {File} file
28658          */
28659         "inspect" : true,
28660         /**
28661          * @event exception
28662          * Fire when xhr load exception
28663          * @param {Roo.bootstrap.DocumentManager} this
28664          * @param {XMLHttpRequest} xhr
28665          */
28666         "exception" : true,
28667         /**
28668          * @event afterupload
28669          * Fire when xhr load exception
28670          * @param {Roo.bootstrap.DocumentManager} this
28671          * @param {XMLHttpRequest} xhr
28672          */
28673         "afterupload" : true,
28674         /**
28675          * @event prepare
28676          * prepare the form data
28677          * @param {Roo.bootstrap.DocumentManager} this
28678          * @param {Object} formData
28679          */
28680         "prepare" : true,
28681         /**
28682          * @event remove
28683          * Fire when remove the file
28684          * @param {Roo.bootstrap.DocumentManager} this
28685          * @param {Object} file
28686          */
28687         "remove" : true,
28688         /**
28689          * @event refresh
28690          * Fire after refresh the file
28691          * @param {Roo.bootstrap.DocumentManager} this
28692          */
28693         "refresh" : true,
28694         /**
28695          * @event click
28696          * Fire after click the image
28697          * @param {Roo.bootstrap.DocumentManager} this
28698          * @param {Object} file
28699          */
28700         "click" : true,
28701         /**
28702          * @event edit
28703          * Fire when upload a image and editable set to true
28704          * @param {Roo.bootstrap.DocumentManager} this
28705          * @param {Object} file
28706          */
28707         "edit" : true,
28708         /**
28709          * @event beforeselectfile
28710          * Fire before select file
28711          * @param {Roo.bootstrap.DocumentManager} this
28712          */
28713         "beforeselectfile" : true,
28714         /**
28715          * @event process
28716          * Fire before process file
28717          * @param {Roo.bootstrap.DocumentManager} this
28718          * @param {Object} file
28719          */
28720         "process" : true,
28721         /**
28722          * @event previewrendered
28723          * Fire when preview rendered
28724          * @param {Roo.bootstrap.DocumentManager} this
28725          * @param {Object} file
28726          */
28727         "previewrendered" : true,
28728         /**
28729          */
28730         "previewResize" : true
28731         
28732     });
28733 };
28734
28735 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28736     
28737     boxes : 0,
28738     inputName : '',
28739     thumbSize : 300,
28740     multiple : true,
28741     files : false,
28742     method : 'POST',
28743     url : '',
28744     paramName : 'imageUpload',
28745     toolTipName : 'filename',
28746     fieldLabel : '',
28747     labelWidth : 4,
28748     labelAlign : 'left',
28749     editable : true,
28750     delegates : false,
28751     xhr : false, 
28752     
28753     labellg : 0,
28754     labelmd : 0,
28755     labelsm : 0,
28756     labelxs : 0,
28757     
28758     getAutoCreate : function()
28759     {   
28760         var managerWidget = {
28761             tag : 'div',
28762             cls : 'roo-document-manager',
28763             cn : [
28764                 {
28765                     tag : 'input',
28766                     cls : 'roo-document-manager-selector',
28767                     type : 'file'
28768                 },
28769                 {
28770                     tag : 'div',
28771                     cls : 'roo-document-manager-uploader',
28772                     cn : [
28773                         {
28774                             tag : 'div',
28775                             cls : 'roo-document-manager-upload-btn',
28776                             html : '<i class="fa fa-plus"></i>'
28777                         }
28778                     ]
28779                     
28780                 }
28781             ]
28782         };
28783         
28784         var content = [
28785             {
28786                 tag : 'div',
28787                 cls : 'column col-md-12',
28788                 cn : managerWidget
28789             }
28790         ];
28791         
28792         if(this.fieldLabel.length){
28793             
28794             content = [
28795                 {
28796                     tag : 'div',
28797                     cls : 'column col-md-12',
28798                     html : this.fieldLabel
28799                 },
28800                 {
28801                     tag : 'div',
28802                     cls : 'column col-md-12',
28803                     cn : managerWidget
28804                 }
28805             ];
28806
28807             if(this.labelAlign == 'left'){
28808                 content = [
28809                     {
28810                         tag : 'div',
28811                         cls : 'column',
28812                         html : this.fieldLabel
28813                     },
28814                     {
28815                         tag : 'div',
28816                         cls : 'column',
28817                         cn : managerWidget
28818                     }
28819                 ];
28820                 
28821                 if(this.labelWidth > 12){
28822                     content[0].style = "width: " + this.labelWidth + 'px';
28823                 }
28824
28825                 if(this.labelWidth < 13 && this.labelmd == 0){
28826                     this.labelmd = this.labelWidth;
28827                 }
28828
28829                 if(this.labellg > 0){
28830                     content[0].cls += ' col-lg-' + this.labellg;
28831                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28832                 }
28833
28834                 if(this.labelmd > 0){
28835                     content[0].cls += ' col-md-' + this.labelmd;
28836                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28837                 }
28838
28839                 if(this.labelsm > 0){
28840                     content[0].cls += ' col-sm-' + this.labelsm;
28841                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28842                 }
28843
28844                 if(this.labelxs > 0){
28845                     content[0].cls += ' col-xs-' + this.labelxs;
28846                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28847                 }
28848                 
28849             }
28850         }
28851         
28852         var cfg = {
28853             tag : 'div',
28854             cls : 'row clearfix',
28855             cn : content
28856         };
28857         
28858         return cfg;
28859         
28860     },
28861     
28862     initEvents : function()
28863     {
28864         this.managerEl = this.el.select('.roo-document-manager', true).first();
28865         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28866         
28867         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28868         this.selectorEl.hide();
28869         
28870         if(this.multiple){
28871             this.selectorEl.attr('multiple', 'multiple');
28872         }
28873         
28874         this.selectorEl.on('change', this.onFileSelected, this);
28875         
28876         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28877         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28878         
28879         this.uploader.on('click', this.onUploaderClick, this);
28880         
28881         this.renderProgressDialog();
28882         
28883         var _this = this;
28884         
28885         window.addEventListener("resize", function() { _this.refresh(); } );
28886         
28887         this.fireEvent('initial', this);
28888     },
28889     
28890     renderProgressDialog : function()
28891     {
28892         var _this = this;
28893         
28894         this.progressDialog = new Roo.bootstrap.Modal({
28895             cls : 'roo-document-manager-progress-dialog',
28896             allow_close : false,
28897             title : '',
28898             buttons : [
28899                 {
28900                     name  :'cancel',
28901                     weight : 'danger',
28902                     html : 'Cancel'
28903                 }
28904             ], 
28905             listeners : { 
28906                 btnclick : function() {
28907                     _this.uploadCancel();
28908                     this.hide();
28909                 }
28910             }
28911         });
28912          
28913         this.progressDialog.render(Roo.get(document.body));
28914          
28915         this.progress = new Roo.bootstrap.Progress({
28916             cls : 'roo-document-manager-progress',
28917             active : true,
28918             striped : true
28919         });
28920         
28921         this.progress.render(this.progressDialog.getChildContainer());
28922         
28923         this.progressBar = new Roo.bootstrap.ProgressBar({
28924             cls : 'roo-document-manager-progress-bar',
28925             aria_valuenow : 0,
28926             aria_valuemin : 0,
28927             aria_valuemax : 12,
28928             panel : 'success'
28929         });
28930         
28931         this.progressBar.render(this.progress.getChildContainer());
28932     },
28933     
28934     onUploaderClick : function(e)
28935     {
28936         e.preventDefault();
28937      
28938         if(this.fireEvent('beforeselectfile', this) != false){
28939             this.selectorEl.dom.click();
28940         }
28941         
28942     },
28943     
28944     onFileSelected : function(e)
28945     {
28946         e.preventDefault();
28947         
28948         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28949             return;
28950         }
28951         
28952         Roo.each(this.selectorEl.dom.files, function(file){
28953             if(this.fireEvent('inspect', this, file) != false){
28954                 this.files.push(file);
28955             }
28956         }, this);
28957         
28958         this.queue();
28959         
28960     },
28961     
28962     queue : function()
28963     {
28964         this.selectorEl.dom.value = '';
28965         
28966         if(!this.files || !this.files.length){
28967             return;
28968         }
28969         
28970         if(this.boxes > 0 && this.files.length > this.boxes){
28971             this.files = this.files.slice(0, this.boxes);
28972         }
28973         
28974         this.uploader.show();
28975         
28976         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28977             this.uploader.hide();
28978         }
28979         
28980         var _this = this;
28981         
28982         var files = [];
28983         
28984         var docs = [];
28985         
28986         Roo.each(this.files, function(file){
28987             
28988             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28989                 var f = this.renderPreview(file);
28990                 files.push(f);
28991                 return;
28992             }
28993             
28994             if(file.type.indexOf('image') != -1){
28995                 this.delegates.push(
28996                     (function(){
28997                         _this.process(file);
28998                     }).createDelegate(this)
28999                 );
29000         
29001                 return;
29002             }
29003             
29004             docs.push(
29005                 (function(){
29006                     _this.process(file);
29007                 }).createDelegate(this)
29008             );
29009             
29010         }, this);
29011         
29012         this.files = files;
29013         
29014         this.delegates = this.delegates.concat(docs);
29015         
29016         if(!this.delegates.length){
29017             this.refresh();
29018             return;
29019         }
29020         
29021         this.progressBar.aria_valuemax = this.delegates.length;
29022         
29023         this.arrange();
29024         
29025         return;
29026     },
29027     
29028     arrange : function()
29029     {
29030         if(!this.delegates.length){
29031             this.progressDialog.hide();
29032             this.refresh();
29033             return;
29034         }
29035         
29036         var delegate = this.delegates.shift();
29037         
29038         this.progressDialog.show();
29039         
29040         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29041         
29042         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29043         
29044         delegate();
29045     },
29046     
29047     refresh : function()
29048     {
29049         this.uploader.show();
29050         
29051         if(this.boxes > 0 && this.files.length > this.boxes - 1){
29052             this.uploader.hide();
29053         }
29054         
29055         Roo.isTouch ? this.closable(false) : this.closable(true);
29056         
29057         this.fireEvent('refresh', this);
29058     },
29059     
29060     onRemove : function(e, el, o)
29061     {
29062         e.preventDefault();
29063         
29064         this.fireEvent('remove', this, o);
29065         
29066     },
29067     
29068     remove : function(o)
29069     {
29070         var files = [];
29071         
29072         Roo.each(this.files, function(file){
29073             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29074                 files.push(file);
29075                 return;
29076             }
29077
29078             o.target.remove();
29079
29080         }, this);
29081         
29082         this.files = files;
29083         
29084         this.refresh();
29085     },
29086     
29087     clear : function()
29088     {
29089         Roo.each(this.files, function(file){
29090             if(!file.target){
29091                 return;
29092             }
29093             
29094             file.target.remove();
29095
29096         }, this);
29097         
29098         this.files = [];
29099         
29100         this.refresh();
29101     },
29102     
29103     onClick : function(e, el, o)
29104     {
29105         e.preventDefault();
29106         
29107         this.fireEvent('click', this, o);
29108         
29109     },
29110     
29111     closable : function(closable)
29112     {
29113         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29114             
29115             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29116             
29117             if(closable){
29118                 el.show();
29119                 return;
29120             }
29121             
29122             el.hide();
29123             
29124         }, this);
29125     },
29126     
29127     xhrOnLoad : function(xhr)
29128     {
29129         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29130             el.remove();
29131         }, this);
29132         
29133         if (xhr.readyState !== 4) {
29134             this.arrange();
29135             this.fireEvent('exception', this, xhr);
29136             return;
29137         }
29138
29139         var response = Roo.decode(xhr.responseText);
29140         
29141         if(!response.success){
29142             this.arrange();
29143             this.fireEvent('exception', this, xhr);
29144             return;
29145         }
29146         
29147         var file = this.renderPreview(response.data);
29148         
29149         this.files.push(file);
29150         
29151         this.arrange();
29152         
29153         this.fireEvent('afterupload', this, xhr);
29154         
29155     },
29156     
29157     xhrOnError : function(xhr)
29158     {
29159         Roo.log('xhr on error');
29160         
29161         var response = Roo.decode(xhr.responseText);
29162           
29163         Roo.log(response);
29164         
29165         this.arrange();
29166     },
29167     
29168     process : function(file)
29169     {
29170         if(this.fireEvent('process', this, file) !== false){
29171             if(this.editable && file.type.indexOf('image') != -1){
29172                 this.fireEvent('edit', this, file);
29173                 return;
29174             }
29175
29176             this.uploadStart(file, false);
29177
29178             return;
29179         }
29180         
29181     },
29182     
29183     uploadStart : function(file, crop)
29184     {
29185         this.xhr = new XMLHttpRequest();
29186         
29187         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29188             this.arrange();
29189             return;
29190         }
29191         
29192         file.xhr = this.xhr;
29193             
29194         this.managerEl.createChild({
29195             tag : 'div',
29196             cls : 'roo-document-manager-loading',
29197             cn : [
29198                 {
29199                     tag : 'div',
29200                     tooltip : file.name,
29201                     cls : 'roo-document-manager-thumb',
29202                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29203                 }
29204             ]
29205
29206         });
29207
29208         this.xhr.open(this.method, this.url, true);
29209         
29210         var headers = {
29211             "Accept": "application/json",
29212             "Cache-Control": "no-cache",
29213             "X-Requested-With": "XMLHttpRequest"
29214         };
29215         
29216         for (var headerName in headers) {
29217             var headerValue = headers[headerName];
29218             if (headerValue) {
29219                 this.xhr.setRequestHeader(headerName, headerValue);
29220             }
29221         }
29222         
29223         var _this = this;
29224         
29225         this.xhr.onload = function()
29226         {
29227             _this.xhrOnLoad(_this.xhr);
29228         }
29229         
29230         this.xhr.onerror = function()
29231         {
29232             _this.xhrOnError(_this.xhr);
29233         }
29234         
29235         var formData = new FormData();
29236
29237         formData.append('returnHTML', 'NO');
29238         
29239         if(crop){
29240             formData.append('crop', crop);
29241         }
29242         
29243         formData.append(this.paramName, file, file.name);
29244         
29245         var options = {
29246             file : file, 
29247             manually : false
29248         };
29249         
29250         if(this.fireEvent('prepare', this, formData, options) != false){
29251             
29252             if(options.manually){
29253                 return;
29254             }
29255             
29256             this.xhr.send(formData);
29257             return;
29258         };
29259         
29260         this.uploadCancel();
29261     },
29262     
29263     uploadCancel : function()
29264     {
29265         if (this.xhr) {
29266             this.xhr.abort();
29267         }
29268         
29269         this.delegates = [];
29270         
29271         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29272             el.remove();
29273         }, this);
29274         
29275         this.arrange();
29276     },
29277     
29278     renderPreview : function(file)
29279     {
29280         if(typeof(file.target) != 'undefined' && file.target){
29281             return file;
29282         }
29283         
29284         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29285         
29286         var previewEl = this.managerEl.createChild({
29287             tag : 'div',
29288             cls : 'roo-document-manager-preview',
29289             cn : [
29290                 {
29291                     tag : 'div',
29292                     tooltip : file[this.toolTipName],
29293                     cls : 'roo-document-manager-thumb',
29294                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29295                 },
29296                 {
29297                     tag : 'button',
29298                     cls : 'close',
29299                     html : '<i class="fa fa-times-circle"></i>'
29300                 }
29301             ]
29302         });
29303
29304         var close = previewEl.select('button.close', true).first();
29305
29306         close.on('click', this.onRemove, this, file);
29307
29308         file.target = previewEl;
29309
29310         var image = previewEl.select('img', true).first();
29311         
29312         var _this = this;
29313         
29314         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29315         
29316         image.on('click', this.onClick, this, file);
29317         
29318         this.fireEvent('previewrendered', this, file);
29319         
29320         return file;
29321         
29322     },
29323     
29324     onPreviewLoad : function(file, image)
29325     {
29326         if(typeof(file.target) == 'undefined' || !file.target){
29327             return;
29328         }
29329         
29330         var width = image.dom.naturalWidth || image.dom.width;
29331         var height = image.dom.naturalHeight || image.dom.height;
29332         
29333         if(!this.previewResize) {
29334             return;
29335         }
29336         
29337         if(width > height){
29338             file.target.addClass('wide');
29339             return;
29340         }
29341         
29342         file.target.addClass('tall');
29343         return;
29344         
29345     },
29346     
29347     uploadFromSource : function(file, crop)
29348     {
29349         this.xhr = new XMLHttpRequest();
29350         
29351         this.managerEl.createChild({
29352             tag : 'div',
29353             cls : 'roo-document-manager-loading',
29354             cn : [
29355                 {
29356                     tag : 'div',
29357                     tooltip : file.name,
29358                     cls : 'roo-document-manager-thumb',
29359                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29360                 }
29361             ]
29362
29363         });
29364
29365         this.xhr.open(this.method, this.url, true);
29366         
29367         var headers = {
29368             "Accept": "application/json",
29369             "Cache-Control": "no-cache",
29370             "X-Requested-With": "XMLHttpRequest"
29371         };
29372         
29373         for (var headerName in headers) {
29374             var headerValue = headers[headerName];
29375             if (headerValue) {
29376                 this.xhr.setRequestHeader(headerName, headerValue);
29377             }
29378         }
29379         
29380         var _this = this;
29381         
29382         this.xhr.onload = function()
29383         {
29384             _this.xhrOnLoad(_this.xhr);
29385         }
29386         
29387         this.xhr.onerror = function()
29388         {
29389             _this.xhrOnError(_this.xhr);
29390         }
29391         
29392         var formData = new FormData();
29393
29394         formData.append('returnHTML', 'NO');
29395         
29396         formData.append('crop', crop);
29397         
29398         if(typeof(file.filename) != 'undefined'){
29399             formData.append('filename', file.filename);
29400         }
29401         
29402         if(typeof(file.mimetype) != 'undefined'){
29403             formData.append('mimetype', file.mimetype);
29404         }
29405         
29406         Roo.log(formData);
29407         
29408         if(this.fireEvent('prepare', this, formData) != false){
29409             this.xhr.send(formData);
29410         };
29411     }
29412 });
29413
29414 /*
29415 * Licence: LGPL
29416 */
29417
29418 /**
29419  * @class Roo.bootstrap.DocumentViewer
29420  * @extends Roo.bootstrap.Component
29421  * Bootstrap DocumentViewer class
29422  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29423  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29424  * 
29425  * @constructor
29426  * Create a new DocumentViewer
29427  * @param {Object} config The config object
29428  */
29429
29430 Roo.bootstrap.DocumentViewer = function(config){
29431     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29432     
29433     this.addEvents({
29434         /**
29435          * @event initial
29436          * Fire after initEvent
29437          * @param {Roo.bootstrap.DocumentViewer} this
29438          */
29439         "initial" : true,
29440         /**
29441          * @event click
29442          * Fire after click
29443          * @param {Roo.bootstrap.DocumentViewer} this
29444          */
29445         "click" : true,
29446         /**
29447          * @event download
29448          * Fire after download button
29449          * @param {Roo.bootstrap.DocumentViewer} this
29450          */
29451         "download" : true,
29452         /**
29453          * @event trash
29454          * Fire after trash button
29455          * @param {Roo.bootstrap.DocumentViewer} this
29456          */
29457         "trash" : true
29458         
29459     });
29460 };
29461
29462 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29463     
29464     showDownload : true,
29465     
29466     showTrash : true,
29467     
29468     getAutoCreate : function()
29469     {
29470         var cfg = {
29471             tag : 'div',
29472             cls : 'roo-document-viewer',
29473             cn : [
29474                 {
29475                     tag : 'div',
29476                     cls : 'roo-document-viewer-body',
29477                     cn : [
29478                         {
29479                             tag : 'div',
29480                             cls : 'roo-document-viewer-thumb',
29481                             cn : [
29482                                 {
29483                                     tag : 'img',
29484                                     cls : 'roo-document-viewer-image'
29485                                 }
29486                             ]
29487                         }
29488                     ]
29489                 },
29490                 {
29491                     tag : 'div',
29492                     cls : 'roo-document-viewer-footer',
29493                     cn : {
29494                         tag : 'div',
29495                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29496                         cn : [
29497                             {
29498                                 tag : 'div',
29499                                 cls : 'btn-group roo-document-viewer-download',
29500                                 cn : [
29501                                     {
29502                                         tag : 'button',
29503                                         cls : 'btn btn-default',
29504                                         html : '<i class="fa fa-download"></i>'
29505                                     }
29506                                 ]
29507                             },
29508                             {
29509                                 tag : 'div',
29510                                 cls : 'btn-group roo-document-viewer-trash',
29511                                 cn : [
29512                                     {
29513                                         tag : 'button',
29514                                         cls : 'btn btn-default',
29515                                         html : '<i class="fa fa-trash"></i>'
29516                                     }
29517                                 ]
29518                             }
29519                         ]
29520                     }
29521                 }
29522             ]
29523         };
29524         
29525         return cfg;
29526     },
29527     
29528     initEvents : function()
29529     {
29530         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29531         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29532         
29533         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29534         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29535         
29536         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29537         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29538         
29539         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29540         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29541         
29542         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29543         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29544         
29545         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29546         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29547         
29548         this.bodyEl.on('click', this.onClick, this);
29549         this.downloadBtn.on('click', this.onDownload, this);
29550         this.trashBtn.on('click', this.onTrash, this);
29551         
29552         this.downloadBtn.hide();
29553         this.trashBtn.hide();
29554         
29555         if(this.showDownload){
29556             this.downloadBtn.show();
29557         }
29558         
29559         if(this.showTrash){
29560             this.trashBtn.show();
29561         }
29562         
29563         if(!this.showDownload && !this.showTrash) {
29564             this.footerEl.hide();
29565         }
29566         
29567     },
29568     
29569     initial : function()
29570     {
29571         this.fireEvent('initial', this);
29572         
29573     },
29574     
29575     onClick : function(e)
29576     {
29577         e.preventDefault();
29578         
29579         this.fireEvent('click', this);
29580     },
29581     
29582     onDownload : function(e)
29583     {
29584         e.preventDefault();
29585         
29586         this.fireEvent('download', this);
29587     },
29588     
29589     onTrash : function(e)
29590     {
29591         e.preventDefault();
29592         
29593         this.fireEvent('trash', this);
29594     }
29595     
29596 });
29597 /*
29598  * - LGPL
29599  *
29600  * nav progress bar
29601  * 
29602  */
29603
29604 /**
29605  * @class Roo.bootstrap.NavProgressBar
29606  * @extends Roo.bootstrap.Component
29607  * Bootstrap NavProgressBar class
29608  * 
29609  * @constructor
29610  * Create a new nav progress bar
29611  * @param {Object} config The config object
29612  */
29613
29614 Roo.bootstrap.NavProgressBar = function(config){
29615     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29616
29617     this.bullets = this.bullets || [];
29618    
29619 //    Roo.bootstrap.NavProgressBar.register(this);
29620      this.addEvents({
29621         /**
29622              * @event changed
29623              * Fires when the active item changes
29624              * @param {Roo.bootstrap.NavProgressBar} this
29625              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29626              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29627          */
29628         'changed': true
29629      });
29630     
29631 };
29632
29633 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29634     
29635     bullets : [],
29636     barItems : [],
29637     
29638     getAutoCreate : function()
29639     {
29640         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29641         
29642         cfg = {
29643             tag : 'div',
29644             cls : 'roo-navigation-bar-group',
29645             cn : [
29646                 {
29647                     tag : 'div',
29648                     cls : 'roo-navigation-top-bar'
29649                 },
29650                 {
29651                     tag : 'div',
29652                     cls : 'roo-navigation-bullets-bar',
29653                     cn : [
29654                         {
29655                             tag : 'ul',
29656                             cls : 'roo-navigation-bar'
29657                         }
29658                     ]
29659                 },
29660                 
29661                 {
29662                     tag : 'div',
29663                     cls : 'roo-navigation-bottom-bar'
29664                 }
29665             ]
29666             
29667         };
29668         
29669         return cfg;
29670         
29671     },
29672     
29673     initEvents: function() 
29674     {
29675         
29676     },
29677     
29678     onRender : function(ct, position) 
29679     {
29680         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29681         
29682         if(this.bullets.length){
29683             Roo.each(this.bullets, function(b){
29684                this.addItem(b);
29685             }, this);
29686         }
29687         
29688         this.format();
29689         
29690     },
29691     
29692     addItem : function(cfg)
29693     {
29694         var item = new Roo.bootstrap.NavProgressItem(cfg);
29695         
29696         item.parentId = this.id;
29697         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29698         
29699         if(cfg.html){
29700             var top = new Roo.bootstrap.Element({
29701                 tag : 'div',
29702                 cls : 'roo-navigation-bar-text'
29703             });
29704             
29705             var bottom = new Roo.bootstrap.Element({
29706                 tag : 'div',
29707                 cls : 'roo-navigation-bar-text'
29708             });
29709             
29710             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29711             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29712             
29713             var topText = new Roo.bootstrap.Element({
29714                 tag : 'span',
29715                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29716             });
29717             
29718             var bottomText = new Roo.bootstrap.Element({
29719                 tag : 'span',
29720                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29721             });
29722             
29723             topText.onRender(top.el, null);
29724             bottomText.onRender(bottom.el, null);
29725             
29726             item.topEl = top;
29727             item.bottomEl = bottom;
29728         }
29729         
29730         this.barItems.push(item);
29731         
29732         return item;
29733     },
29734     
29735     getActive : function()
29736     {
29737         var active = false;
29738         
29739         Roo.each(this.barItems, function(v){
29740             
29741             if (!v.isActive()) {
29742                 return;
29743             }
29744             
29745             active = v;
29746             return false;
29747             
29748         });
29749         
29750         return active;
29751     },
29752     
29753     setActiveItem : function(item)
29754     {
29755         var prev = false;
29756         
29757         Roo.each(this.barItems, function(v){
29758             if (v.rid == item.rid) {
29759                 return ;
29760             }
29761             
29762             if (v.isActive()) {
29763                 v.setActive(false);
29764                 prev = v;
29765             }
29766         });
29767
29768         item.setActive(true);
29769         
29770         this.fireEvent('changed', this, item, prev);
29771     },
29772     
29773     getBarItem: function(rid)
29774     {
29775         var ret = false;
29776         
29777         Roo.each(this.barItems, function(e) {
29778             if (e.rid != rid) {
29779                 return;
29780             }
29781             
29782             ret =  e;
29783             return false;
29784         });
29785         
29786         return ret;
29787     },
29788     
29789     indexOfItem : function(item)
29790     {
29791         var index = false;
29792         
29793         Roo.each(this.barItems, function(v, i){
29794             
29795             if (v.rid != item.rid) {
29796                 return;
29797             }
29798             
29799             index = i;
29800             return false
29801         });
29802         
29803         return index;
29804     },
29805     
29806     setActiveNext : function()
29807     {
29808         var i = this.indexOfItem(this.getActive());
29809         
29810         if (i > this.barItems.length) {
29811             return;
29812         }
29813         
29814         this.setActiveItem(this.barItems[i+1]);
29815     },
29816     
29817     setActivePrev : function()
29818     {
29819         var i = this.indexOfItem(this.getActive());
29820         
29821         if (i  < 1) {
29822             return;
29823         }
29824         
29825         this.setActiveItem(this.barItems[i-1]);
29826     },
29827     
29828     format : function()
29829     {
29830         if(!this.barItems.length){
29831             return;
29832         }
29833      
29834         var width = 100 / this.barItems.length;
29835         
29836         Roo.each(this.barItems, function(i){
29837             i.el.setStyle('width', width + '%');
29838             i.topEl.el.setStyle('width', width + '%');
29839             i.bottomEl.el.setStyle('width', width + '%');
29840         }, this);
29841         
29842     }
29843     
29844 });
29845 /*
29846  * - LGPL
29847  *
29848  * Nav Progress Item
29849  * 
29850  */
29851
29852 /**
29853  * @class Roo.bootstrap.NavProgressItem
29854  * @extends Roo.bootstrap.Component
29855  * Bootstrap NavProgressItem class
29856  * @cfg {String} rid the reference id
29857  * @cfg {Boolean} active (true|false) Is item active default false
29858  * @cfg {Boolean} disabled (true|false) Is item active default false
29859  * @cfg {String} html
29860  * @cfg {String} position (top|bottom) text position default bottom
29861  * @cfg {String} icon show icon instead of number
29862  * 
29863  * @constructor
29864  * Create a new NavProgressItem
29865  * @param {Object} config The config object
29866  */
29867 Roo.bootstrap.NavProgressItem = function(config){
29868     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29869     this.addEvents({
29870         // raw events
29871         /**
29872          * @event click
29873          * The raw click event for the entire grid.
29874          * @param {Roo.bootstrap.NavProgressItem} this
29875          * @param {Roo.EventObject} e
29876          */
29877         "click" : true
29878     });
29879    
29880 };
29881
29882 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29883     
29884     rid : '',
29885     active : false,
29886     disabled : false,
29887     html : '',
29888     position : 'bottom',
29889     icon : false,
29890     
29891     getAutoCreate : function()
29892     {
29893         var iconCls = 'roo-navigation-bar-item-icon';
29894         
29895         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29896         
29897         var cfg = {
29898             tag: 'li',
29899             cls: 'roo-navigation-bar-item',
29900             cn : [
29901                 {
29902                     tag : 'i',
29903                     cls : iconCls
29904                 }
29905             ]
29906         };
29907         
29908         if(this.active){
29909             cfg.cls += ' active';
29910         }
29911         if(this.disabled){
29912             cfg.cls += ' disabled';
29913         }
29914         
29915         return cfg;
29916     },
29917     
29918     disable : function()
29919     {
29920         this.setDisabled(true);
29921     },
29922     
29923     enable : function()
29924     {
29925         this.setDisabled(false);
29926     },
29927     
29928     initEvents: function() 
29929     {
29930         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29931         
29932         this.iconEl.on('click', this.onClick, this);
29933     },
29934     
29935     onClick : function(e)
29936     {
29937         e.preventDefault();
29938         
29939         if(this.disabled){
29940             return;
29941         }
29942         
29943         if(this.fireEvent('click', this, e) === false){
29944             return;
29945         };
29946         
29947         this.parent().setActiveItem(this);
29948     },
29949     
29950     isActive: function () 
29951     {
29952         return this.active;
29953     },
29954     
29955     setActive : function(state)
29956     {
29957         if(this.active == state){
29958             return;
29959         }
29960         
29961         this.active = state;
29962         
29963         if (state) {
29964             this.el.addClass('active');
29965             return;
29966         }
29967         
29968         this.el.removeClass('active');
29969         
29970         return;
29971     },
29972     
29973     setDisabled : function(state)
29974     {
29975         if(this.disabled == state){
29976             return;
29977         }
29978         
29979         this.disabled = state;
29980         
29981         if (state) {
29982             this.el.addClass('disabled');
29983             return;
29984         }
29985         
29986         this.el.removeClass('disabled');
29987     },
29988     
29989     tooltipEl : function()
29990     {
29991         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29992     }
29993 });
29994  
29995
29996  /*
29997  * - LGPL
29998  *
29999  * FieldLabel
30000  * 
30001  */
30002
30003 /**
30004  * @class Roo.bootstrap.FieldLabel
30005  * @extends Roo.bootstrap.Component
30006  * Bootstrap FieldLabel class
30007  * @cfg {String} html contents of the element
30008  * @cfg {String} tag tag of the element default label
30009  * @cfg {String} cls class of the element
30010  * @cfg {String} target label target 
30011  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30012  * @cfg {String} invalidClass default "text-warning"
30013  * @cfg {String} validClass default "text-success"
30014  * @cfg {String} iconTooltip default "This field is required"
30015  * @cfg {String} indicatorpos (left|right) default left
30016  * 
30017  * @constructor
30018  * Create a new FieldLabel
30019  * @param {Object} config The config object
30020  */
30021
30022 Roo.bootstrap.FieldLabel = function(config){
30023     Roo.bootstrap.Element.superclass.constructor.call(this, config);
30024     
30025     this.addEvents({
30026             /**
30027              * @event invalid
30028              * Fires after the field has been marked as invalid.
30029              * @param {Roo.form.FieldLabel} this
30030              * @param {String} msg The validation message
30031              */
30032             invalid : true,
30033             /**
30034              * @event valid
30035              * Fires after the field has been validated with no errors.
30036              * @param {Roo.form.FieldLabel} this
30037              */
30038             valid : true
30039         });
30040 };
30041
30042 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
30043     
30044     tag: 'label',
30045     cls: '',
30046     html: '',
30047     target: '',
30048     allowBlank : true,
30049     invalidClass : 'has-warning',
30050     validClass : 'has-success',
30051     iconTooltip : 'This field is required',
30052     indicatorpos : 'left',
30053     
30054     getAutoCreate : function(){
30055         
30056         var cls = "";
30057         if (!this.allowBlank) {
30058             cls  = "visible";
30059         }
30060         
30061         var cfg = {
30062             tag : this.tag,
30063             cls : 'roo-bootstrap-field-label ' + this.cls,
30064             for : this.target,
30065             cn : [
30066                 {
30067                     tag : 'i',
30068                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30069                     tooltip : this.iconTooltip
30070                 },
30071                 {
30072                     tag : 'span',
30073                     html : this.html
30074                 }
30075             ] 
30076         };
30077         
30078         if(this.indicatorpos == 'right'){
30079             var cfg = {
30080                 tag : this.tag,
30081                 cls : 'roo-bootstrap-field-label ' + this.cls,
30082                 for : this.target,
30083                 cn : [
30084                     {
30085                         tag : 'span',
30086                         html : this.html
30087                     },
30088                     {
30089                         tag : 'i',
30090                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30091                         tooltip : this.iconTooltip
30092                     }
30093                 ] 
30094             };
30095         }
30096         
30097         return cfg;
30098     },
30099     
30100     initEvents: function() 
30101     {
30102         Roo.bootstrap.Element.superclass.initEvents.call(this);
30103         
30104         this.indicator = this.indicatorEl();
30105         
30106         if(this.indicator){
30107             this.indicator.removeClass('visible');
30108             this.indicator.addClass('invisible');
30109         }
30110         
30111         Roo.bootstrap.FieldLabel.register(this);
30112     },
30113     
30114     indicatorEl : function()
30115     {
30116         var indicator = this.el.select('i.roo-required-indicator',true).first();
30117         
30118         if(!indicator){
30119             return false;
30120         }
30121         
30122         return indicator;
30123         
30124     },
30125     
30126     /**
30127      * Mark this field as valid
30128      */
30129     markValid : function()
30130     {
30131         if(this.indicator){
30132             this.indicator.removeClass('visible');
30133             this.indicator.addClass('invisible');
30134         }
30135         
30136         this.el.removeClass(this.invalidClass);
30137         
30138         this.el.addClass(this.validClass);
30139         
30140         this.fireEvent('valid', this);
30141     },
30142     
30143     /**
30144      * Mark this field as invalid
30145      * @param {String} msg The validation message
30146      */
30147     markInvalid : function(msg)
30148     {
30149         if(this.indicator){
30150             this.indicator.removeClass('invisible');
30151             this.indicator.addClass('visible');
30152         }
30153         
30154         this.el.removeClass(this.validClass);
30155         
30156         this.el.addClass(this.invalidClass);
30157         
30158         this.fireEvent('invalid', this, msg);
30159     }
30160     
30161    
30162 });
30163
30164 Roo.apply(Roo.bootstrap.FieldLabel, {
30165     
30166     groups: {},
30167     
30168      /**
30169     * register a FieldLabel Group
30170     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30171     */
30172     register : function(label)
30173     {
30174         if(this.groups.hasOwnProperty(label.target)){
30175             return;
30176         }
30177      
30178         this.groups[label.target] = label;
30179         
30180     },
30181     /**
30182     * fetch a FieldLabel Group based on the target
30183     * @param {string} target
30184     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30185     */
30186     get: function(target) {
30187         if (typeof(this.groups[target]) == 'undefined') {
30188             return false;
30189         }
30190         
30191         return this.groups[target] ;
30192     }
30193 });
30194
30195  
30196
30197  /*
30198  * - LGPL
30199  *
30200  * page DateSplitField.
30201  * 
30202  */
30203
30204
30205 /**
30206  * @class Roo.bootstrap.DateSplitField
30207  * @extends Roo.bootstrap.Component
30208  * Bootstrap DateSplitField class
30209  * @cfg {string} fieldLabel - the label associated
30210  * @cfg {Number} labelWidth set the width of label (0-12)
30211  * @cfg {String} labelAlign (top|left)
30212  * @cfg {Boolean} dayAllowBlank (true|false) default false
30213  * @cfg {Boolean} monthAllowBlank (true|false) default false
30214  * @cfg {Boolean} yearAllowBlank (true|false) default false
30215  * @cfg {string} dayPlaceholder 
30216  * @cfg {string} monthPlaceholder
30217  * @cfg {string} yearPlaceholder
30218  * @cfg {string} dayFormat default 'd'
30219  * @cfg {string} monthFormat default 'm'
30220  * @cfg {string} yearFormat default 'Y'
30221  * @cfg {Number} labellg set the width of label (1-12)
30222  * @cfg {Number} labelmd set the width of label (1-12)
30223  * @cfg {Number} labelsm set the width of label (1-12)
30224  * @cfg {Number} labelxs set the width of label (1-12)
30225
30226  *     
30227  * @constructor
30228  * Create a new DateSplitField
30229  * @param {Object} config The config object
30230  */
30231
30232 Roo.bootstrap.DateSplitField = function(config){
30233     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30234     
30235     this.addEvents({
30236         // raw events
30237          /**
30238          * @event years
30239          * getting the data of years
30240          * @param {Roo.bootstrap.DateSplitField} this
30241          * @param {Object} years
30242          */
30243         "years" : true,
30244         /**
30245          * @event days
30246          * getting the data of days
30247          * @param {Roo.bootstrap.DateSplitField} this
30248          * @param {Object} days
30249          */
30250         "days" : true,
30251         /**
30252          * @event invalid
30253          * Fires after the field has been marked as invalid.
30254          * @param {Roo.form.Field} this
30255          * @param {String} msg The validation message
30256          */
30257         invalid : true,
30258        /**
30259          * @event valid
30260          * Fires after the field has been validated with no errors.
30261          * @param {Roo.form.Field} this
30262          */
30263         valid : true
30264     });
30265 };
30266
30267 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30268     
30269     fieldLabel : '',
30270     labelAlign : 'top',
30271     labelWidth : 3,
30272     dayAllowBlank : false,
30273     monthAllowBlank : false,
30274     yearAllowBlank : false,
30275     dayPlaceholder : '',
30276     monthPlaceholder : '',
30277     yearPlaceholder : '',
30278     dayFormat : 'd',
30279     monthFormat : 'm',
30280     yearFormat : 'Y',
30281     isFormField : true,
30282     labellg : 0,
30283     labelmd : 0,
30284     labelsm : 0,
30285     labelxs : 0,
30286     
30287     getAutoCreate : function()
30288     {
30289         var cfg = {
30290             tag : 'div',
30291             cls : 'row roo-date-split-field-group',
30292             cn : [
30293                 {
30294                     tag : 'input',
30295                     type : 'hidden',
30296                     cls : 'form-hidden-field roo-date-split-field-group-value',
30297                     name : this.name
30298                 }
30299             ]
30300         };
30301         
30302         var labelCls = 'col-md-12';
30303         var contentCls = 'col-md-4';
30304         
30305         if(this.fieldLabel){
30306             
30307             var label = {
30308                 tag : 'div',
30309                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30310                 cn : [
30311                     {
30312                         tag : 'label',
30313                         html : this.fieldLabel
30314                     }
30315                 ]
30316             };
30317             
30318             if(this.labelAlign == 'left'){
30319             
30320                 if(this.labelWidth > 12){
30321                     label.style = "width: " + this.labelWidth + 'px';
30322                 }
30323
30324                 if(this.labelWidth < 13 && this.labelmd == 0){
30325                     this.labelmd = this.labelWidth;
30326                 }
30327
30328                 if(this.labellg > 0){
30329                     labelCls = ' col-lg-' + this.labellg;
30330                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30331                 }
30332
30333                 if(this.labelmd > 0){
30334                     labelCls = ' col-md-' + this.labelmd;
30335                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30336                 }
30337
30338                 if(this.labelsm > 0){
30339                     labelCls = ' col-sm-' + this.labelsm;
30340                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30341                 }
30342
30343                 if(this.labelxs > 0){
30344                     labelCls = ' col-xs-' + this.labelxs;
30345                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30346                 }
30347             }
30348             
30349             label.cls += ' ' + labelCls;
30350             
30351             cfg.cn.push(label);
30352         }
30353         
30354         Roo.each(['day', 'month', 'year'], function(t){
30355             cfg.cn.push({
30356                 tag : 'div',
30357                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30358             });
30359         }, this);
30360         
30361         return cfg;
30362     },
30363     
30364     inputEl: function ()
30365     {
30366         return this.el.select('.roo-date-split-field-group-value', true).first();
30367     },
30368     
30369     onRender : function(ct, position) 
30370     {
30371         var _this = this;
30372         
30373         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30374         
30375         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30376         
30377         this.dayField = new Roo.bootstrap.ComboBox({
30378             allowBlank : this.dayAllowBlank,
30379             alwaysQuery : true,
30380             displayField : 'value',
30381             editable : false,
30382             fieldLabel : '',
30383             forceSelection : true,
30384             mode : 'local',
30385             placeholder : this.dayPlaceholder,
30386             selectOnFocus : true,
30387             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30388             triggerAction : 'all',
30389             typeAhead : true,
30390             valueField : 'value',
30391             store : new Roo.data.SimpleStore({
30392                 data : (function() {    
30393                     var days = [];
30394                     _this.fireEvent('days', _this, days);
30395                     return days;
30396                 })(),
30397                 fields : [ 'value' ]
30398             }),
30399             listeners : {
30400                 select : function (_self, record, index)
30401                 {
30402                     _this.setValue(_this.getValue());
30403                 }
30404             }
30405         });
30406
30407         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30408         
30409         this.monthField = new Roo.bootstrap.MonthField({
30410             after : '<i class=\"fa fa-calendar\"></i>',
30411             allowBlank : this.monthAllowBlank,
30412             placeholder : this.monthPlaceholder,
30413             readOnly : true,
30414             listeners : {
30415                 render : function (_self)
30416                 {
30417                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30418                         e.preventDefault();
30419                         _self.focus();
30420                     });
30421                 },
30422                 select : function (_self, oldvalue, newvalue)
30423                 {
30424                     _this.setValue(_this.getValue());
30425                 }
30426             }
30427         });
30428         
30429         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30430         
30431         this.yearField = new Roo.bootstrap.ComboBox({
30432             allowBlank : this.yearAllowBlank,
30433             alwaysQuery : true,
30434             displayField : 'value',
30435             editable : false,
30436             fieldLabel : '',
30437             forceSelection : true,
30438             mode : 'local',
30439             placeholder : this.yearPlaceholder,
30440             selectOnFocus : true,
30441             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30442             triggerAction : 'all',
30443             typeAhead : true,
30444             valueField : 'value',
30445             store : new Roo.data.SimpleStore({
30446                 data : (function() {
30447                     var years = [];
30448                     _this.fireEvent('years', _this, years);
30449                     return years;
30450                 })(),
30451                 fields : [ 'value' ]
30452             }),
30453             listeners : {
30454                 select : function (_self, record, index)
30455                 {
30456                     _this.setValue(_this.getValue());
30457                 }
30458             }
30459         });
30460
30461         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30462     },
30463     
30464     setValue : function(v, format)
30465     {
30466         this.inputEl.dom.value = v;
30467         
30468         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30469         
30470         var d = Date.parseDate(v, f);
30471         
30472         if(!d){
30473             this.validate();
30474             return;
30475         }
30476         
30477         this.setDay(d.format(this.dayFormat));
30478         this.setMonth(d.format(this.monthFormat));
30479         this.setYear(d.format(this.yearFormat));
30480         
30481         this.validate();
30482         
30483         return;
30484     },
30485     
30486     setDay : function(v)
30487     {
30488         this.dayField.setValue(v);
30489         this.inputEl.dom.value = this.getValue();
30490         this.validate();
30491         return;
30492     },
30493     
30494     setMonth : function(v)
30495     {
30496         this.monthField.setValue(v, true);
30497         this.inputEl.dom.value = this.getValue();
30498         this.validate();
30499         return;
30500     },
30501     
30502     setYear : function(v)
30503     {
30504         this.yearField.setValue(v);
30505         this.inputEl.dom.value = this.getValue();
30506         this.validate();
30507         return;
30508     },
30509     
30510     getDay : function()
30511     {
30512         return this.dayField.getValue();
30513     },
30514     
30515     getMonth : function()
30516     {
30517         return this.monthField.getValue();
30518     },
30519     
30520     getYear : function()
30521     {
30522         return this.yearField.getValue();
30523     },
30524     
30525     getValue : function()
30526     {
30527         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30528         
30529         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30530         
30531         return date;
30532     },
30533     
30534     reset : function()
30535     {
30536         this.setDay('');
30537         this.setMonth('');
30538         this.setYear('');
30539         this.inputEl.dom.value = '';
30540         this.validate();
30541         return;
30542     },
30543     
30544     validate : function()
30545     {
30546         var d = this.dayField.validate();
30547         var m = this.monthField.validate();
30548         var y = this.yearField.validate();
30549         
30550         var valid = true;
30551         
30552         if(
30553                 (!this.dayAllowBlank && !d) ||
30554                 (!this.monthAllowBlank && !m) ||
30555                 (!this.yearAllowBlank && !y)
30556         ){
30557             valid = false;
30558         }
30559         
30560         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30561             return valid;
30562         }
30563         
30564         if(valid){
30565             this.markValid();
30566             return valid;
30567         }
30568         
30569         this.markInvalid();
30570         
30571         return valid;
30572     },
30573     
30574     markValid : function()
30575     {
30576         
30577         var label = this.el.select('label', true).first();
30578         var icon = this.el.select('i.fa-star', true).first();
30579
30580         if(label && icon){
30581             icon.remove();
30582         }
30583         
30584         this.fireEvent('valid', this);
30585     },
30586     
30587      /**
30588      * Mark this field as invalid
30589      * @param {String} msg The validation message
30590      */
30591     markInvalid : function(msg)
30592     {
30593         
30594         var label = this.el.select('label', true).first();
30595         var icon = this.el.select('i.fa-star', true).first();
30596
30597         if(label && !icon){
30598             this.el.select('.roo-date-split-field-label', true).createChild({
30599                 tag : 'i',
30600                 cls : 'text-danger fa fa-lg fa-star',
30601                 tooltip : 'This field is required',
30602                 style : 'margin-right:5px;'
30603             }, label, true);
30604         }
30605         
30606         this.fireEvent('invalid', this, msg);
30607     },
30608     
30609     clearInvalid : function()
30610     {
30611         var label = this.el.select('label', true).first();
30612         var icon = this.el.select('i.fa-star', true).first();
30613
30614         if(label && icon){
30615             icon.remove();
30616         }
30617         
30618         this.fireEvent('valid', this);
30619     },
30620     
30621     getName: function()
30622     {
30623         return this.name;
30624     }
30625     
30626 });
30627
30628  /**
30629  *
30630  * This is based on 
30631  * http://masonry.desandro.com
30632  *
30633  * The idea is to render all the bricks based on vertical width...
30634  *
30635  * The original code extends 'outlayer' - we might need to use that....
30636  * 
30637  */
30638
30639
30640 /**
30641  * @class Roo.bootstrap.LayoutMasonry
30642  * @extends Roo.bootstrap.Component
30643  * Bootstrap Layout Masonry class
30644  * 
30645  * @constructor
30646  * Create a new Element
30647  * @param {Object} config The config object
30648  */
30649
30650 Roo.bootstrap.LayoutMasonry = function(config){
30651     
30652     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30653     
30654     this.bricks = [];
30655     
30656     Roo.bootstrap.LayoutMasonry.register(this);
30657     
30658     this.addEvents({
30659         // raw events
30660         /**
30661          * @event layout
30662          * Fire after layout the items
30663          * @param {Roo.bootstrap.LayoutMasonry} this
30664          * @param {Roo.EventObject} e
30665          */
30666         "layout" : true
30667     });
30668     
30669 };
30670
30671 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30672     
30673     /**
30674      * @cfg {Boolean} isLayoutInstant = no animation?
30675      */   
30676     isLayoutInstant : false, // needed?
30677    
30678     /**
30679      * @cfg {Number} boxWidth  width of the columns
30680      */   
30681     boxWidth : 450,
30682     
30683       /**
30684      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30685      */   
30686     boxHeight : 0,
30687     
30688     /**
30689      * @cfg {Number} padWidth padding below box..
30690      */   
30691     padWidth : 10, 
30692     
30693     /**
30694      * @cfg {Number} gutter gutter width..
30695      */   
30696     gutter : 10,
30697     
30698      /**
30699      * @cfg {Number} maxCols maximum number of columns
30700      */   
30701     
30702     maxCols: 0,
30703     
30704     /**
30705      * @cfg {Boolean} isAutoInitial defalut true
30706      */   
30707     isAutoInitial : true, 
30708     
30709     containerWidth: 0,
30710     
30711     /**
30712      * @cfg {Boolean} isHorizontal defalut false
30713      */   
30714     isHorizontal : false, 
30715
30716     currentSize : null,
30717     
30718     tag: 'div',
30719     
30720     cls: '',
30721     
30722     bricks: null, //CompositeElement
30723     
30724     cols : 1,
30725     
30726     _isLayoutInited : false,
30727     
30728 //    isAlternative : false, // only use for vertical layout...
30729     
30730     /**
30731      * @cfg {Number} alternativePadWidth padding below box..
30732      */   
30733     alternativePadWidth : 50,
30734     
30735     selectedBrick : [],
30736     
30737     getAutoCreate : function(){
30738         
30739         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30740         
30741         var cfg = {
30742             tag: this.tag,
30743             cls: 'blog-masonary-wrapper ' + this.cls,
30744             cn : {
30745                 cls : 'mas-boxes masonary'
30746             }
30747         };
30748         
30749         return cfg;
30750     },
30751     
30752     getChildContainer: function( )
30753     {
30754         if (this.boxesEl) {
30755             return this.boxesEl;
30756         }
30757         
30758         this.boxesEl = this.el.select('.mas-boxes').first();
30759         
30760         return this.boxesEl;
30761     },
30762     
30763     
30764     initEvents : function()
30765     {
30766         var _this = this;
30767         
30768         if(this.isAutoInitial){
30769             Roo.log('hook children rendered');
30770             this.on('childrenrendered', function() {
30771                 Roo.log('children rendered');
30772                 _this.initial();
30773             } ,this);
30774         }
30775     },
30776     
30777     initial : function()
30778     {
30779         this.selectedBrick = [];
30780         
30781         this.currentSize = this.el.getBox(true);
30782         
30783         Roo.EventManager.onWindowResize(this.resize, this); 
30784
30785         if(!this.isAutoInitial){
30786             this.layout();
30787             return;
30788         }
30789         
30790         this.layout();
30791         
30792         return;
30793         //this.layout.defer(500,this);
30794         
30795     },
30796     
30797     resize : function()
30798     {
30799         var cs = this.el.getBox(true);
30800         
30801         if (
30802                 this.currentSize.width == cs.width && 
30803                 this.currentSize.x == cs.x && 
30804                 this.currentSize.height == cs.height && 
30805                 this.currentSize.y == cs.y 
30806         ) {
30807             Roo.log("no change in with or X or Y");
30808             return;
30809         }
30810         
30811         this.currentSize = cs;
30812         
30813         this.layout();
30814         
30815     },
30816     
30817     layout : function()
30818     {   
30819         this._resetLayout();
30820         
30821         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30822         
30823         this.layoutItems( isInstant );
30824       
30825         this._isLayoutInited = true;
30826         
30827         this.fireEvent('layout', this);
30828         
30829     },
30830     
30831     _resetLayout : function()
30832     {
30833         if(this.isHorizontal){
30834             this.horizontalMeasureColumns();
30835             return;
30836         }
30837         
30838         this.verticalMeasureColumns();
30839         
30840     },
30841     
30842     verticalMeasureColumns : function()
30843     {
30844         this.getContainerWidth();
30845         
30846 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30847 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30848 //            return;
30849 //        }
30850         
30851         var boxWidth = this.boxWidth + this.padWidth;
30852         
30853         if(this.containerWidth < this.boxWidth){
30854             boxWidth = this.containerWidth
30855         }
30856         
30857         var containerWidth = this.containerWidth;
30858         
30859         var cols = Math.floor(containerWidth / boxWidth);
30860         
30861         this.cols = Math.max( cols, 1 );
30862         
30863         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30864         
30865         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30866         
30867         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30868         
30869         this.colWidth = boxWidth + avail - this.padWidth;
30870         
30871         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30872         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30873     },
30874     
30875     horizontalMeasureColumns : function()
30876     {
30877         this.getContainerWidth();
30878         
30879         var boxWidth = this.boxWidth;
30880         
30881         if(this.containerWidth < boxWidth){
30882             boxWidth = this.containerWidth;
30883         }
30884         
30885         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30886         
30887         this.el.setHeight(boxWidth);
30888         
30889     },
30890     
30891     getContainerWidth : function()
30892     {
30893         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30894     },
30895     
30896     layoutItems : function( isInstant )
30897     {
30898         Roo.log(this.bricks);
30899         
30900         var items = Roo.apply([], this.bricks);
30901         
30902         if(this.isHorizontal){
30903             this._horizontalLayoutItems( items , isInstant );
30904             return;
30905         }
30906         
30907 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30908 //            this._verticalAlternativeLayoutItems( items , isInstant );
30909 //            return;
30910 //        }
30911         
30912         this._verticalLayoutItems( items , isInstant );
30913         
30914     },
30915     
30916     _verticalLayoutItems : function ( items , isInstant)
30917     {
30918         if ( !items || !items.length ) {
30919             return;
30920         }
30921         
30922         var standard = [
30923             ['xs', 'xs', 'xs', 'tall'],
30924             ['xs', 'xs', 'tall'],
30925             ['xs', 'xs', 'sm'],
30926             ['xs', 'xs', 'xs'],
30927             ['xs', 'tall'],
30928             ['xs', 'sm'],
30929             ['xs', 'xs'],
30930             ['xs'],
30931             
30932             ['sm', 'xs', 'xs'],
30933             ['sm', 'xs'],
30934             ['sm'],
30935             
30936             ['tall', 'xs', 'xs', 'xs'],
30937             ['tall', 'xs', 'xs'],
30938             ['tall', 'xs'],
30939             ['tall']
30940             
30941         ];
30942         
30943         var queue = [];
30944         
30945         var boxes = [];
30946         
30947         var box = [];
30948         
30949         Roo.each(items, function(item, k){
30950             
30951             switch (item.size) {
30952                 // these layouts take up a full box,
30953                 case 'md' :
30954                 case 'md-left' :
30955                 case 'md-right' :
30956                 case 'wide' :
30957                     
30958                     if(box.length){
30959                         boxes.push(box);
30960                         box = [];
30961                     }
30962                     
30963                     boxes.push([item]);
30964                     
30965                     break;
30966                     
30967                 case 'xs' :
30968                 case 'sm' :
30969                 case 'tall' :
30970                     
30971                     box.push(item);
30972                     
30973                     break;
30974                 default :
30975                     break;
30976                     
30977             }
30978             
30979         }, this);
30980         
30981         if(box.length){
30982             boxes.push(box);
30983             box = [];
30984         }
30985         
30986         var filterPattern = function(box, length)
30987         {
30988             if(!box.length){
30989                 return;
30990             }
30991             
30992             var match = false;
30993             
30994             var pattern = box.slice(0, length);
30995             
30996             var format = [];
30997             
30998             Roo.each(pattern, function(i){
30999                 format.push(i.size);
31000             }, this);
31001             
31002             Roo.each(standard, function(s){
31003                 
31004                 if(String(s) != String(format)){
31005                     return;
31006                 }
31007                 
31008                 match = true;
31009                 return false;
31010                 
31011             }, this);
31012             
31013             if(!match && length == 1){
31014                 return;
31015             }
31016             
31017             if(!match){
31018                 filterPattern(box, length - 1);
31019                 return;
31020             }
31021                 
31022             queue.push(pattern);
31023
31024             box = box.slice(length, box.length);
31025
31026             filterPattern(box, 4);
31027
31028             return;
31029             
31030         }
31031         
31032         Roo.each(boxes, function(box, k){
31033             
31034             if(!box.length){
31035                 return;
31036             }
31037             
31038             if(box.length == 1){
31039                 queue.push(box);
31040                 return;
31041             }
31042             
31043             filterPattern(box, 4);
31044             
31045         }, this);
31046         
31047         this._processVerticalLayoutQueue( queue, isInstant );
31048         
31049     },
31050     
31051 //    _verticalAlternativeLayoutItems : function( items , isInstant )
31052 //    {
31053 //        if ( !items || !items.length ) {
31054 //            return;
31055 //        }
31056 //
31057 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
31058 //        
31059 //    },
31060     
31061     _horizontalLayoutItems : function ( items , isInstant)
31062     {
31063         if ( !items || !items.length || items.length < 3) {
31064             return;
31065         }
31066         
31067         items.reverse();
31068         
31069         var eItems = items.slice(0, 3);
31070         
31071         items = items.slice(3, items.length);
31072         
31073         var standard = [
31074             ['xs', 'xs', 'xs', 'wide'],
31075             ['xs', 'xs', 'wide'],
31076             ['xs', 'xs', 'sm'],
31077             ['xs', 'xs', 'xs'],
31078             ['xs', 'wide'],
31079             ['xs', 'sm'],
31080             ['xs', 'xs'],
31081             ['xs'],
31082             
31083             ['sm', 'xs', 'xs'],
31084             ['sm', 'xs'],
31085             ['sm'],
31086             
31087             ['wide', 'xs', 'xs', 'xs'],
31088             ['wide', 'xs', 'xs'],
31089             ['wide', 'xs'],
31090             ['wide'],
31091             
31092             ['wide-thin']
31093         ];
31094         
31095         var queue = [];
31096         
31097         var boxes = [];
31098         
31099         var box = [];
31100         
31101         Roo.each(items, function(item, k){
31102             
31103             switch (item.size) {
31104                 case 'md' :
31105                 case 'md-left' :
31106                 case 'md-right' :
31107                 case 'tall' :
31108                     
31109                     if(box.length){
31110                         boxes.push(box);
31111                         box = [];
31112                     }
31113                     
31114                     boxes.push([item]);
31115                     
31116                     break;
31117                     
31118                 case 'xs' :
31119                 case 'sm' :
31120                 case 'wide' :
31121                 case 'wide-thin' :
31122                     
31123                     box.push(item);
31124                     
31125                     break;
31126                 default :
31127                     break;
31128                     
31129             }
31130             
31131         }, this);
31132         
31133         if(box.length){
31134             boxes.push(box);
31135             box = [];
31136         }
31137         
31138         var filterPattern = function(box, length)
31139         {
31140             if(!box.length){
31141                 return;
31142             }
31143             
31144             var match = false;
31145             
31146             var pattern = box.slice(0, length);
31147             
31148             var format = [];
31149             
31150             Roo.each(pattern, function(i){
31151                 format.push(i.size);
31152             }, this);
31153             
31154             Roo.each(standard, function(s){
31155                 
31156                 if(String(s) != String(format)){
31157                     return;
31158                 }
31159                 
31160                 match = true;
31161                 return false;
31162                 
31163             }, this);
31164             
31165             if(!match && length == 1){
31166                 return;
31167             }
31168             
31169             if(!match){
31170                 filterPattern(box, length - 1);
31171                 return;
31172             }
31173                 
31174             queue.push(pattern);
31175
31176             box = box.slice(length, box.length);
31177
31178             filterPattern(box, 4);
31179
31180             return;
31181             
31182         }
31183         
31184         Roo.each(boxes, function(box, k){
31185             
31186             if(!box.length){
31187                 return;
31188             }
31189             
31190             if(box.length == 1){
31191                 queue.push(box);
31192                 return;
31193             }
31194             
31195             filterPattern(box, 4);
31196             
31197         }, this);
31198         
31199         
31200         var prune = [];
31201         
31202         var pos = this.el.getBox(true);
31203         
31204         var minX = pos.x;
31205         
31206         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31207         
31208         var hit_end = false;
31209         
31210         Roo.each(queue, function(box){
31211             
31212             if(hit_end){
31213                 
31214                 Roo.each(box, function(b){
31215                 
31216                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31217                     b.el.hide();
31218
31219                 }, this);
31220
31221                 return;
31222             }
31223             
31224             var mx = 0;
31225             
31226             Roo.each(box, function(b){
31227                 
31228                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31229                 b.el.show();
31230
31231                 mx = Math.max(mx, b.x);
31232                 
31233             }, this);
31234             
31235             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31236             
31237             if(maxX < minX){
31238                 
31239                 Roo.each(box, function(b){
31240                 
31241                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31242                     b.el.hide();
31243                     
31244                 }, this);
31245                 
31246                 hit_end = true;
31247                 
31248                 return;
31249             }
31250             
31251             prune.push(box);
31252             
31253         }, this);
31254         
31255         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31256     },
31257     
31258     /** Sets position of item in DOM
31259     * @param {Element} item
31260     * @param {Number} x - horizontal position
31261     * @param {Number} y - vertical position
31262     * @param {Boolean} isInstant - disables transitions
31263     */
31264     _processVerticalLayoutQueue : function( queue, isInstant )
31265     {
31266         var pos = this.el.getBox(true);
31267         var x = pos.x;
31268         var y = pos.y;
31269         var maxY = [];
31270         
31271         for (var i = 0; i < this.cols; i++){
31272             maxY[i] = pos.y;
31273         }
31274         
31275         Roo.each(queue, function(box, k){
31276             
31277             var col = k % this.cols;
31278             
31279             Roo.each(box, function(b,kk){
31280                 
31281                 b.el.position('absolute');
31282                 
31283                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31284                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31285                 
31286                 if(b.size == 'md-left' || b.size == 'md-right'){
31287                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31288                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31289                 }
31290                 
31291                 b.el.setWidth(width);
31292                 b.el.setHeight(height);
31293                 // iframe?
31294                 b.el.select('iframe',true).setSize(width,height);
31295                 
31296             }, this);
31297             
31298             for (var i = 0; i < this.cols; i++){
31299                 
31300                 if(maxY[i] < maxY[col]){
31301                     col = i;
31302                     continue;
31303                 }
31304                 
31305                 col = Math.min(col, i);
31306                 
31307             }
31308             
31309             x = pos.x + col * (this.colWidth + this.padWidth);
31310             
31311             y = maxY[col];
31312             
31313             var positions = [];
31314             
31315             switch (box.length){
31316                 case 1 :
31317                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31318                     break;
31319                 case 2 :
31320                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31321                     break;
31322                 case 3 :
31323                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31324                     break;
31325                 case 4 :
31326                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31327                     break;
31328                 default :
31329                     break;
31330             }
31331             
31332             Roo.each(box, function(b,kk){
31333                 
31334                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31335                 
31336                 var sz = b.el.getSize();
31337                 
31338                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31339                 
31340             }, this);
31341             
31342         }, this);
31343         
31344         var mY = 0;
31345         
31346         for (var i = 0; i < this.cols; i++){
31347             mY = Math.max(mY, maxY[i]);
31348         }
31349         
31350         this.el.setHeight(mY - pos.y);
31351         
31352     },
31353     
31354 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31355 //    {
31356 //        var pos = this.el.getBox(true);
31357 //        var x = pos.x;
31358 //        var y = pos.y;
31359 //        var maxX = pos.right;
31360 //        
31361 //        var maxHeight = 0;
31362 //        
31363 //        Roo.each(items, function(item, k){
31364 //            
31365 //            var c = k % 2;
31366 //            
31367 //            item.el.position('absolute');
31368 //                
31369 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31370 //
31371 //            item.el.setWidth(width);
31372 //
31373 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31374 //
31375 //            item.el.setHeight(height);
31376 //            
31377 //            if(c == 0){
31378 //                item.el.setXY([x, y], isInstant ? false : true);
31379 //            } else {
31380 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31381 //            }
31382 //            
31383 //            y = y + height + this.alternativePadWidth;
31384 //            
31385 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31386 //            
31387 //        }, this);
31388 //        
31389 //        this.el.setHeight(maxHeight);
31390 //        
31391 //    },
31392     
31393     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31394     {
31395         var pos = this.el.getBox(true);
31396         
31397         var minX = pos.x;
31398         var minY = pos.y;
31399         
31400         var maxX = pos.right;
31401         
31402         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31403         
31404         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31405         
31406         Roo.each(queue, function(box, k){
31407             
31408             Roo.each(box, function(b, kk){
31409                 
31410                 b.el.position('absolute');
31411                 
31412                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31413                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31414                 
31415                 if(b.size == 'md-left' || b.size == 'md-right'){
31416                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31417                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31418                 }
31419                 
31420                 b.el.setWidth(width);
31421                 b.el.setHeight(height);
31422                 
31423             }, this);
31424             
31425             if(!box.length){
31426                 return;
31427             }
31428             
31429             var positions = [];
31430             
31431             switch (box.length){
31432                 case 1 :
31433                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31434                     break;
31435                 case 2 :
31436                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31437                     break;
31438                 case 3 :
31439                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31440                     break;
31441                 case 4 :
31442                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31443                     break;
31444                 default :
31445                     break;
31446             }
31447             
31448             Roo.each(box, function(b,kk){
31449                 
31450                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31451                 
31452                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31453                 
31454             }, this);
31455             
31456         }, this);
31457         
31458     },
31459     
31460     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31461     {
31462         Roo.each(eItems, function(b,k){
31463             
31464             b.size = (k == 0) ? 'sm' : 'xs';
31465             b.x = (k == 0) ? 2 : 1;
31466             b.y = (k == 0) ? 2 : 1;
31467             
31468             b.el.position('absolute');
31469             
31470             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31471                 
31472             b.el.setWidth(width);
31473             
31474             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31475             
31476             b.el.setHeight(height);
31477             
31478         }, this);
31479
31480         var positions = [];
31481         
31482         positions.push({
31483             x : maxX - this.unitWidth * 2 - this.gutter,
31484             y : minY
31485         });
31486         
31487         positions.push({
31488             x : maxX - this.unitWidth,
31489             y : minY + (this.unitWidth + this.gutter) * 2
31490         });
31491         
31492         positions.push({
31493             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31494             y : minY
31495         });
31496         
31497         Roo.each(eItems, function(b,k){
31498             
31499             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31500
31501         }, this);
31502         
31503     },
31504     
31505     getVerticalOneBoxColPositions : function(x, y, box)
31506     {
31507         var pos = [];
31508         
31509         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31510         
31511         if(box[0].size == 'md-left'){
31512             rand = 0;
31513         }
31514         
31515         if(box[0].size == 'md-right'){
31516             rand = 1;
31517         }
31518         
31519         pos.push({
31520             x : x + (this.unitWidth + this.gutter) * rand,
31521             y : y
31522         });
31523         
31524         return pos;
31525     },
31526     
31527     getVerticalTwoBoxColPositions : function(x, y, box)
31528     {
31529         var pos = [];
31530         
31531         if(box[0].size == 'xs'){
31532             
31533             pos.push({
31534                 x : x,
31535                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31536             });
31537
31538             pos.push({
31539                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31540                 y : y
31541             });
31542             
31543             return pos;
31544             
31545         }
31546         
31547         pos.push({
31548             x : x,
31549             y : y
31550         });
31551
31552         pos.push({
31553             x : x + (this.unitWidth + this.gutter) * 2,
31554             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31555         });
31556         
31557         return pos;
31558         
31559     },
31560     
31561     getVerticalThreeBoxColPositions : function(x, y, box)
31562     {
31563         var pos = [];
31564         
31565         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31566             
31567             pos.push({
31568                 x : x,
31569                 y : y
31570             });
31571
31572             pos.push({
31573                 x : x + (this.unitWidth + this.gutter) * 1,
31574                 y : y
31575             });
31576             
31577             pos.push({
31578                 x : x + (this.unitWidth + this.gutter) * 2,
31579                 y : y
31580             });
31581             
31582             return pos;
31583             
31584         }
31585         
31586         if(box[0].size == 'xs' && box[1].size == 'xs'){
31587             
31588             pos.push({
31589                 x : x,
31590                 y : y
31591             });
31592
31593             pos.push({
31594                 x : x,
31595                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31596             });
31597             
31598             pos.push({
31599                 x : x + (this.unitWidth + this.gutter) * 1,
31600                 y : y
31601             });
31602             
31603             return pos;
31604             
31605         }
31606         
31607         pos.push({
31608             x : x,
31609             y : y
31610         });
31611
31612         pos.push({
31613             x : x + (this.unitWidth + this.gutter) * 2,
31614             y : y
31615         });
31616
31617         pos.push({
31618             x : x + (this.unitWidth + this.gutter) * 2,
31619             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31620         });
31621             
31622         return pos;
31623         
31624     },
31625     
31626     getVerticalFourBoxColPositions : function(x, y, box)
31627     {
31628         var pos = [];
31629         
31630         if(box[0].size == 'xs'){
31631             
31632             pos.push({
31633                 x : x,
31634                 y : y
31635             });
31636
31637             pos.push({
31638                 x : x,
31639                 y : y + (this.unitHeight + this.gutter) * 1
31640             });
31641             
31642             pos.push({
31643                 x : x,
31644                 y : y + (this.unitHeight + this.gutter) * 2
31645             });
31646             
31647             pos.push({
31648                 x : x + (this.unitWidth + this.gutter) * 1,
31649                 y : y
31650             });
31651             
31652             return pos;
31653             
31654         }
31655         
31656         pos.push({
31657             x : x,
31658             y : y
31659         });
31660
31661         pos.push({
31662             x : x + (this.unitWidth + this.gutter) * 2,
31663             y : y
31664         });
31665
31666         pos.push({
31667             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31668             y : y + (this.unitHeight + this.gutter) * 1
31669         });
31670
31671         pos.push({
31672             x : x + (this.unitWidth + this.gutter) * 2,
31673             y : y + (this.unitWidth + this.gutter) * 2
31674         });
31675
31676         return pos;
31677         
31678     },
31679     
31680     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31681     {
31682         var pos = [];
31683         
31684         if(box[0].size == 'md-left'){
31685             pos.push({
31686                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31687                 y : minY
31688             });
31689             
31690             return pos;
31691         }
31692         
31693         if(box[0].size == 'md-right'){
31694             pos.push({
31695                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31696                 y : minY + (this.unitWidth + this.gutter) * 1
31697             });
31698             
31699             return pos;
31700         }
31701         
31702         var rand = Math.floor(Math.random() * (4 - box[0].y));
31703         
31704         pos.push({
31705             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31706             y : minY + (this.unitWidth + this.gutter) * rand
31707         });
31708         
31709         return pos;
31710         
31711     },
31712     
31713     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31714     {
31715         var pos = [];
31716         
31717         if(box[0].size == 'xs'){
31718             
31719             pos.push({
31720                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31721                 y : minY
31722             });
31723
31724             pos.push({
31725                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31726                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31727             });
31728             
31729             return pos;
31730             
31731         }
31732         
31733         pos.push({
31734             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31735             y : minY
31736         });
31737
31738         pos.push({
31739             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31740             y : minY + (this.unitWidth + this.gutter) * 2
31741         });
31742         
31743         return pos;
31744         
31745     },
31746     
31747     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31748     {
31749         var pos = [];
31750         
31751         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31752             
31753             pos.push({
31754                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31755                 y : minY
31756             });
31757
31758             pos.push({
31759                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31760                 y : minY + (this.unitWidth + this.gutter) * 1
31761             });
31762             
31763             pos.push({
31764                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31765                 y : minY + (this.unitWidth + this.gutter) * 2
31766             });
31767             
31768             return pos;
31769             
31770         }
31771         
31772         if(box[0].size == 'xs' && box[1].size == 'xs'){
31773             
31774             pos.push({
31775                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31776                 y : minY
31777             });
31778
31779             pos.push({
31780                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31781                 y : minY
31782             });
31783             
31784             pos.push({
31785                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31786                 y : minY + (this.unitWidth + this.gutter) * 1
31787             });
31788             
31789             return pos;
31790             
31791         }
31792         
31793         pos.push({
31794             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31795             y : minY
31796         });
31797
31798         pos.push({
31799             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31800             y : minY + (this.unitWidth + this.gutter) * 2
31801         });
31802
31803         pos.push({
31804             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31805             y : minY + (this.unitWidth + this.gutter) * 2
31806         });
31807             
31808         return pos;
31809         
31810     },
31811     
31812     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31813     {
31814         var pos = [];
31815         
31816         if(box[0].size == 'xs'){
31817             
31818             pos.push({
31819                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31820                 y : minY
31821             });
31822
31823             pos.push({
31824                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31825                 y : minY
31826             });
31827             
31828             pos.push({
31829                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31830                 y : minY
31831             });
31832             
31833             pos.push({
31834                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31835                 y : minY + (this.unitWidth + this.gutter) * 1
31836             });
31837             
31838             return pos;
31839             
31840         }
31841         
31842         pos.push({
31843             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31844             y : minY
31845         });
31846         
31847         pos.push({
31848             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31849             y : minY + (this.unitWidth + this.gutter) * 2
31850         });
31851         
31852         pos.push({
31853             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31854             y : minY + (this.unitWidth + this.gutter) * 2
31855         });
31856         
31857         pos.push({
31858             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31859             y : minY + (this.unitWidth + this.gutter) * 2
31860         });
31861
31862         return pos;
31863         
31864     },
31865     
31866     /**
31867     * remove a Masonry Brick
31868     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31869     */
31870     removeBrick : function(brick_id)
31871     {
31872         if (!brick_id) {
31873             return;
31874         }
31875         
31876         for (var i = 0; i<this.bricks.length; i++) {
31877             if (this.bricks[i].id == brick_id) {
31878                 this.bricks.splice(i,1);
31879                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31880                 this.initial();
31881             }
31882         }
31883     },
31884     
31885     /**
31886     * adds a Masonry Brick
31887     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31888     */
31889     addBrick : function(cfg)
31890     {
31891         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31892         //this.register(cn);
31893         cn.parentId = this.id;
31894         cn.onRender(this.el, null);
31895         return cn;
31896     },
31897     
31898     /**
31899     * register a Masonry Brick
31900     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31901     */
31902     
31903     register : function(brick)
31904     {
31905         this.bricks.push(brick);
31906         brick.masonryId = this.id;
31907     },
31908     
31909     /**
31910     * clear all the Masonry Brick
31911     */
31912     clearAll : function()
31913     {
31914         this.bricks = [];
31915         //this.getChildContainer().dom.innerHTML = "";
31916         this.el.dom.innerHTML = '';
31917     },
31918     
31919     getSelected : function()
31920     {
31921         if (!this.selectedBrick) {
31922             return false;
31923         }
31924         
31925         return this.selectedBrick;
31926     }
31927 });
31928
31929 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31930     
31931     groups: {},
31932      /**
31933     * register a Masonry Layout
31934     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31935     */
31936     
31937     register : function(layout)
31938     {
31939         this.groups[layout.id] = layout;
31940     },
31941     /**
31942     * fetch a  Masonry Layout based on the masonry layout ID
31943     * @param {string} the masonry layout to add
31944     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31945     */
31946     
31947     get: function(layout_id) {
31948         if (typeof(this.groups[layout_id]) == 'undefined') {
31949             return false;
31950         }
31951         return this.groups[layout_id] ;
31952     }
31953     
31954     
31955     
31956 });
31957
31958  
31959
31960  /**
31961  *
31962  * This is based on 
31963  * http://masonry.desandro.com
31964  *
31965  * The idea is to render all the bricks based on vertical width...
31966  *
31967  * The original code extends 'outlayer' - we might need to use that....
31968  * 
31969  */
31970
31971
31972 /**
31973  * @class Roo.bootstrap.LayoutMasonryAuto
31974  * @extends Roo.bootstrap.Component
31975  * Bootstrap Layout Masonry class
31976  * 
31977  * @constructor
31978  * Create a new Element
31979  * @param {Object} config The config object
31980  */
31981
31982 Roo.bootstrap.LayoutMasonryAuto = function(config){
31983     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31984 };
31985
31986 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31987     
31988       /**
31989      * @cfg {Boolean} isFitWidth  - resize the width..
31990      */   
31991     isFitWidth : false,  // options..
31992     /**
31993      * @cfg {Boolean} isOriginLeft = left align?
31994      */   
31995     isOriginLeft : true,
31996     /**
31997      * @cfg {Boolean} isOriginTop = top align?
31998      */   
31999     isOriginTop : false,
32000     /**
32001      * @cfg {Boolean} isLayoutInstant = no animation?
32002      */   
32003     isLayoutInstant : false, // needed?
32004     /**
32005      * @cfg {Boolean} isResizingContainer = not sure if this is used..
32006      */   
32007     isResizingContainer : true,
32008     /**
32009      * @cfg {Number} columnWidth  width of the columns 
32010      */   
32011     
32012     columnWidth : 0,
32013     
32014     /**
32015      * @cfg {Number} maxCols maximum number of columns
32016      */   
32017     
32018     maxCols: 0,
32019     /**
32020      * @cfg {Number} padHeight padding below box..
32021      */   
32022     
32023     padHeight : 10, 
32024     
32025     /**
32026      * @cfg {Boolean} isAutoInitial defalut true
32027      */   
32028     
32029     isAutoInitial : true, 
32030     
32031     // private?
32032     gutter : 0,
32033     
32034     containerWidth: 0,
32035     initialColumnWidth : 0,
32036     currentSize : null,
32037     
32038     colYs : null, // array.
32039     maxY : 0,
32040     padWidth: 10,
32041     
32042     
32043     tag: 'div',
32044     cls: '',
32045     bricks: null, //CompositeElement
32046     cols : 0, // array?
32047     // element : null, // wrapped now this.el
32048     _isLayoutInited : null, 
32049     
32050     
32051     getAutoCreate : function(){
32052         
32053         var cfg = {
32054             tag: this.tag,
32055             cls: 'blog-masonary-wrapper ' + this.cls,
32056             cn : {
32057                 cls : 'mas-boxes masonary'
32058             }
32059         };
32060         
32061         return cfg;
32062     },
32063     
32064     getChildContainer: function( )
32065     {
32066         if (this.boxesEl) {
32067             return this.boxesEl;
32068         }
32069         
32070         this.boxesEl = this.el.select('.mas-boxes').first();
32071         
32072         return this.boxesEl;
32073     },
32074     
32075     
32076     initEvents : function()
32077     {
32078         var _this = this;
32079         
32080         if(this.isAutoInitial){
32081             Roo.log('hook children rendered');
32082             this.on('childrenrendered', function() {
32083                 Roo.log('children rendered');
32084                 _this.initial();
32085             } ,this);
32086         }
32087         
32088     },
32089     
32090     initial : function()
32091     {
32092         this.reloadItems();
32093
32094         this.currentSize = this.el.getBox(true);
32095
32096         /// was window resize... - let's see if this works..
32097         Roo.EventManager.onWindowResize(this.resize, this); 
32098
32099         if(!this.isAutoInitial){
32100             this.layout();
32101             return;
32102         }
32103         
32104         this.layout.defer(500,this);
32105     },
32106     
32107     reloadItems: function()
32108     {
32109         this.bricks = this.el.select('.masonry-brick', true);
32110         
32111         this.bricks.each(function(b) {
32112             //Roo.log(b.getSize());
32113             if (!b.attr('originalwidth')) {
32114                 b.attr('originalwidth',  b.getSize().width);
32115             }
32116             
32117         });
32118         
32119         Roo.log(this.bricks.elements.length);
32120     },
32121     
32122     resize : function()
32123     {
32124         Roo.log('resize');
32125         var cs = this.el.getBox(true);
32126         
32127         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32128             Roo.log("no change in with or X");
32129             return;
32130         }
32131         this.currentSize = cs;
32132         this.layout();
32133     },
32134     
32135     layout : function()
32136     {
32137          Roo.log('layout');
32138         this._resetLayout();
32139         //this._manageStamps();
32140       
32141         // don't animate first layout
32142         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32143         this.layoutItems( isInstant );
32144       
32145         // flag for initalized
32146         this._isLayoutInited = true;
32147     },
32148     
32149     layoutItems : function( isInstant )
32150     {
32151         //var items = this._getItemsForLayout( this.items );
32152         // original code supports filtering layout items.. we just ignore it..
32153         
32154         this._layoutItems( this.bricks , isInstant );
32155       
32156         this._postLayout();
32157     },
32158     _layoutItems : function ( items , isInstant)
32159     {
32160        //this.fireEvent( 'layout', this, items );
32161     
32162
32163         if ( !items || !items.elements.length ) {
32164           // no items, emit event with empty array
32165             return;
32166         }
32167
32168         var queue = [];
32169         items.each(function(item) {
32170             Roo.log("layout item");
32171             Roo.log(item);
32172             // get x/y object from method
32173             var position = this._getItemLayoutPosition( item );
32174             // enqueue
32175             position.item = item;
32176             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32177             queue.push( position );
32178         }, this);
32179       
32180         this._processLayoutQueue( queue );
32181     },
32182     /** Sets position of item in DOM
32183     * @param {Element} item
32184     * @param {Number} x - horizontal position
32185     * @param {Number} y - vertical position
32186     * @param {Boolean} isInstant - disables transitions
32187     */
32188     _processLayoutQueue : function( queue )
32189     {
32190         for ( var i=0, len = queue.length; i < len; i++ ) {
32191             var obj = queue[i];
32192             obj.item.position('absolute');
32193             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32194         }
32195     },
32196       
32197     
32198     /**
32199     * Any logic you want to do after each layout,
32200     * i.e. size the container
32201     */
32202     _postLayout : function()
32203     {
32204         this.resizeContainer();
32205     },
32206     
32207     resizeContainer : function()
32208     {
32209         if ( !this.isResizingContainer ) {
32210             return;
32211         }
32212         var size = this._getContainerSize();
32213         if ( size ) {
32214             this.el.setSize(size.width,size.height);
32215             this.boxesEl.setSize(size.width,size.height);
32216         }
32217     },
32218     
32219     
32220     
32221     _resetLayout : function()
32222     {
32223         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32224         this.colWidth = this.el.getWidth();
32225         //this.gutter = this.el.getWidth(); 
32226         
32227         this.measureColumns();
32228
32229         // reset column Y
32230         var i = this.cols;
32231         this.colYs = [];
32232         while (i--) {
32233             this.colYs.push( 0 );
32234         }
32235     
32236         this.maxY = 0;
32237     },
32238
32239     measureColumns : function()
32240     {
32241         this.getContainerWidth();
32242       // if columnWidth is 0, default to outerWidth of first item
32243         if ( !this.columnWidth ) {
32244             var firstItem = this.bricks.first();
32245             Roo.log(firstItem);
32246             this.columnWidth  = this.containerWidth;
32247             if (firstItem && firstItem.attr('originalwidth') ) {
32248                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32249             }
32250             // columnWidth fall back to item of first element
32251             Roo.log("set column width?");
32252                         this.initialColumnWidth = this.columnWidth  ;
32253
32254             // if first elem has no width, default to size of container
32255             
32256         }
32257         
32258         
32259         if (this.initialColumnWidth) {
32260             this.columnWidth = this.initialColumnWidth;
32261         }
32262         
32263         
32264             
32265         // column width is fixed at the top - however if container width get's smaller we should
32266         // reduce it...
32267         
32268         // this bit calcs how man columns..
32269             
32270         var columnWidth = this.columnWidth += this.gutter;
32271       
32272         // calculate columns
32273         var containerWidth = this.containerWidth + this.gutter;
32274         
32275         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32276         // fix rounding errors, typically with gutters
32277         var excess = columnWidth - containerWidth % columnWidth;
32278         
32279         
32280         // if overshoot is less than a pixel, round up, otherwise floor it
32281         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32282         cols = Math[ mathMethod ]( cols );
32283         this.cols = Math.max( cols, 1 );
32284         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32285         
32286          // padding positioning..
32287         var totalColWidth = this.cols * this.columnWidth;
32288         var padavail = this.containerWidth - totalColWidth;
32289         // so for 2 columns - we need 3 'pads'
32290         
32291         var padNeeded = (1+this.cols) * this.padWidth;
32292         
32293         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32294         
32295         this.columnWidth += padExtra
32296         //this.padWidth = Math.floor(padavail /  ( this.cols));
32297         
32298         // adjust colum width so that padding is fixed??
32299         
32300         // we have 3 columns ... total = width * 3
32301         // we have X left over... that should be used by 
32302         
32303         //if (this.expandC) {
32304             
32305         //}
32306         
32307         
32308         
32309     },
32310     
32311     getContainerWidth : function()
32312     {
32313        /* // container is parent if fit width
32314         var container = this.isFitWidth ? this.element.parentNode : this.element;
32315         // check that this.size and size are there
32316         // IE8 triggers resize on body size change, so they might not be
32317         
32318         var size = getSize( container );  //FIXME
32319         this.containerWidth = size && size.innerWidth; //FIXME
32320         */
32321          
32322         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32323         
32324     },
32325     
32326     _getItemLayoutPosition : function( item )  // what is item?
32327     {
32328         // we resize the item to our columnWidth..
32329       
32330         item.setWidth(this.columnWidth);
32331         item.autoBoxAdjust  = false;
32332         
32333         var sz = item.getSize();
32334  
32335         // how many columns does this brick span
32336         var remainder = this.containerWidth % this.columnWidth;
32337         
32338         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32339         // round if off by 1 pixel, otherwise use ceil
32340         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32341         colSpan = Math.min( colSpan, this.cols );
32342         
32343         // normally this should be '1' as we dont' currently allow multi width columns..
32344         
32345         var colGroup = this._getColGroup( colSpan );
32346         // get the minimum Y value from the columns
32347         var minimumY = Math.min.apply( Math, colGroup );
32348         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32349         
32350         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32351          
32352         // position the brick
32353         var position = {
32354             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32355             y: this.currentSize.y + minimumY + this.padHeight
32356         };
32357         
32358         Roo.log(position);
32359         // apply setHeight to necessary columns
32360         var setHeight = minimumY + sz.height + this.padHeight;
32361         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32362         
32363         var setSpan = this.cols + 1 - colGroup.length;
32364         for ( var i = 0; i < setSpan; i++ ) {
32365           this.colYs[ shortColIndex + i ] = setHeight ;
32366         }
32367       
32368         return position;
32369     },
32370     
32371     /**
32372      * @param {Number} colSpan - number of columns the element spans
32373      * @returns {Array} colGroup
32374      */
32375     _getColGroup : function( colSpan )
32376     {
32377         if ( colSpan < 2 ) {
32378           // if brick spans only one column, use all the column Ys
32379           return this.colYs;
32380         }
32381       
32382         var colGroup = [];
32383         // how many different places could this brick fit horizontally
32384         var groupCount = this.cols + 1 - colSpan;
32385         // for each group potential horizontal position
32386         for ( var i = 0; i < groupCount; i++ ) {
32387           // make an array of colY values for that one group
32388           var groupColYs = this.colYs.slice( i, i + colSpan );
32389           // and get the max value of the array
32390           colGroup[i] = Math.max.apply( Math, groupColYs );
32391         }
32392         return colGroup;
32393     },
32394     /*
32395     _manageStamp : function( stamp )
32396     {
32397         var stampSize =  stamp.getSize();
32398         var offset = stamp.getBox();
32399         // get the columns that this stamp affects
32400         var firstX = this.isOriginLeft ? offset.x : offset.right;
32401         var lastX = firstX + stampSize.width;
32402         var firstCol = Math.floor( firstX / this.columnWidth );
32403         firstCol = Math.max( 0, firstCol );
32404         
32405         var lastCol = Math.floor( lastX / this.columnWidth );
32406         // lastCol should not go over if multiple of columnWidth #425
32407         lastCol -= lastX % this.columnWidth ? 0 : 1;
32408         lastCol = Math.min( this.cols - 1, lastCol );
32409         
32410         // set colYs to bottom of the stamp
32411         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32412             stampSize.height;
32413             
32414         for ( var i = firstCol; i <= lastCol; i++ ) {
32415           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32416         }
32417     },
32418     */
32419     
32420     _getContainerSize : function()
32421     {
32422         this.maxY = Math.max.apply( Math, this.colYs );
32423         var size = {
32424             height: this.maxY
32425         };
32426       
32427         if ( this.isFitWidth ) {
32428             size.width = this._getContainerFitWidth();
32429         }
32430       
32431         return size;
32432     },
32433     
32434     _getContainerFitWidth : function()
32435     {
32436         var unusedCols = 0;
32437         // count unused columns
32438         var i = this.cols;
32439         while ( --i ) {
32440           if ( this.colYs[i] !== 0 ) {
32441             break;
32442           }
32443           unusedCols++;
32444         }
32445         // fit container to columns that have been used
32446         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32447     },
32448     
32449     needsResizeLayout : function()
32450     {
32451         var previousWidth = this.containerWidth;
32452         this.getContainerWidth();
32453         return previousWidth !== this.containerWidth;
32454     }
32455  
32456 });
32457
32458  
32459
32460  /*
32461  * - LGPL
32462  *
32463  * element
32464  * 
32465  */
32466
32467 /**
32468  * @class Roo.bootstrap.MasonryBrick
32469  * @extends Roo.bootstrap.Component
32470  * Bootstrap MasonryBrick class
32471  * 
32472  * @constructor
32473  * Create a new MasonryBrick
32474  * @param {Object} config The config object
32475  */
32476
32477 Roo.bootstrap.MasonryBrick = function(config){
32478     
32479     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32480     
32481     Roo.bootstrap.MasonryBrick.register(this);
32482     
32483     this.addEvents({
32484         // raw events
32485         /**
32486          * @event click
32487          * When a MasonryBrick is clcik
32488          * @param {Roo.bootstrap.MasonryBrick} this
32489          * @param {Roo.EventObject} e
32490          */
32491         "click" : true
32492     });
32493 };
32494
32495 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32496     
32497     /**
32498      * @cfg {String} title
32499      */   
32500     title : '',
32501     /**
32502      * @cfg {String} html
32503      */   
32504     html : '',
32505     /**
32506      * @cfg {String} bgimage
32507      */   
32508     bgimage : '',
32509     /**
32510      * @cfg {String} videourl
32511      */   
32512     videourl : '',
32513     /**
32514      * @cfg {String} cls
32515      */   
32516     cls : '',
32517     /**
32518      * @cfg {String} href
32519      */   
32520     href : '',
32521     /**
32522      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32523      */   
32524     size : 'xs',
32525     
32526     /**
32527      * @cfg {String} placetitle (center|bottom)
32528      */   
32529     placetitle : '',
32530     
32531     /**
32532      * @cfg {Boolean} isFitContainer defalut true
32533      */   
32534     isFitContainer : true, 
32535     
32536     /**
32537      * @cfg {Boolean} preventDefault defalut false
32538      */   
32539     preventDefault : false, 
32540     
32541     /**
32542      * @cfg {Boolean} inverse defalut false
32543      */   
32544     maskInverse : false, 
32545     
32546     getAutoCreate : function()
32547     {
32548         if(!this.isFitContainer){
32549             return this.getSplitAutoCreate();
32550         }
32551         
32552         var cls = 'masonry-brick masonry-brick-full';
32553         
32554         if(this.href.length){
32555             cls += ' masonry-brick-link';
32556         }
32557         
32558         if(this.bgimage.length){
32559             cls += ' masonry-brick-image';
32560         }
32561         
32562         if(this.maskInverse){
32563             cls += ' mask-inverse';
32564         }
32565         
32566         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32567             cls += ' enable-mask';
32568         }
32569         
32570         if(this.size){
32571             cls += ' masonry-' + this.size + '-brick';
32572         }
32573         
32574         if(this.placetitle.length){
32575             
32576             switch (this.placetitle) {
32577                 case 'center' :
32578                     cls += ' masonry-center-title';
32579                     break;
32580                 case 'bottom' :
32581                     cls += ' masonry-bottom-title';
32582                     break;
32583                 default:
32584                     break;
32585             }
32586             
32587         } else {
32588             if(!this.html.length && !this.bgimage.length){
32589                 cls += ' masonry-center-title';
32590             }
32591
32592             if(!this.html.length && this.bgimage.length){
32593                 cls += ' masonry-bottom-title';
32594             }
32595         }
32596         
32597         if(this.cls){
32598             cls += ' ' + this.cls;
32599         }
32600         
32601         var cfg = {
32602             tag: (this.href.length) ? 'a' : 'div',
32603             cls: cls,
32604             cn: [
32605                 {
32606                     tag: 'div',
32607                     cls: 'masonry-brick-mask'
32608                 },
32609                 {
32610                     tag: 'div',
32611                     cls: 'masonry-brick-paragraph',
32612                     cn: []
32613                 }
32614             ]
32615         };
32616         
32617         if(this.href.length){
32618             cfg.href = this.href;
32619         }
32620         
32621         var cn = cfg.cn[1].cn;
32622         
32623         if(this.title.length){
32624             cn.push({
32625                 tag: 'h4',
32626                 cls: 'masonry-brick-title',
32627                 html: this.title
32628             });
32629         }
32630         
32631         if(this.html.length){
32632             cn.push({
32633                 tag: 'p',
32634                 cls: 'masonry-brick-text',
32635                 html: this.html
32636             });
32637         }
32638         
32639         if (!this.title.length && !this.html.length) {
32640             cfg.cn[1].cls += ' hide';
32641         }
32642         
32643         if(this.bgimage.length){
32644             cfg.cn.push({
32645                 tag: 'img',
32646                 cls: 'masonry-brick-image-view',
32647                 src: this.bgimage
32648             });
32649         }
32650         
32651         if(this.videourl.length){
32652             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32653             // youtube support only?
32654             cfg.cn.push({
32655                 tag: 'iframe',
32656                 cls: 'masonry-brick-image-view',
32657                 src: vurl,
32658                 frameborder : 0,
32659                 allowfullscreen : true
32660             });
32661         }
32662         
32663         return cfg;
32664         
32665     },
32666     
32667     getSplitAutoCreate : function()
32668     {
32669         var cls = 'masonry-brick masonry-brick-split';
32670         
32671         if(this.href.length){
32672             cls += ' masonry-brick-link';
32673         }
32674         
32675         if(this.bgimage.length){
32676             cls += ' masonry-brick-image';
32677         }
32678         
32679         if(this.size){
32680             cls += ' masonry-' + this.size + '-brick';
32681         }
32682         
32683         switch (this.placetitle) {
32684             case 'center' :
32685                 cls += ' masonry-center-title';
32686                 break;
32687             case 'bottom' :
32688                 cls += ' masonry-bottom-title';
32689                 break;
32690             default:
32691                 if(!this.bgimage.length){
32692                     cls += ' masonry-center-title';
32693                 }
32694
32695                 if(this.bgimage.length){
32696                     cls += ' masonry-bottom-title';
32697                 }
32698                 break;
32699         }
32700         
32701         if(this.cls){
32702             cls += ' ' + this.cls;
32703         }
32704         
32705         var cfg = {
32706             tag: (this.href.length) ? 'a' : 'div',
32707             cls: cls,
32708             cn: [
32709                 {
32710                     tag: 'div',
32711                     cls: 'masonry-brick-split-head',
32712                     cn: [
32713                         {
32714                             tag: 'div',
32715                             cls: 'masonry-brick-paragraph',
32716                             cn: []
32717                         }
32718                     ]
32719                 },
32720                 {
32721                     tag: 'div',
32722                     cls: 'masonry-brick-split-body',
32723                     cn: []
32724                 }
32725             ]
32726         };
32727         
32728         if(this.href.length){
32729             cfg.href = this.href;
32730         }
32731         
32732         if(this.title.length){
32733             cfg.cn[0].cn[0].cn.push({
32734                 tag: 'h4',
32735                 cls: 'masonry-brick-title',
32736                 html: this.title
32737             });
32738         }
32739         
32740         if(this.html.length){
32741             cfg.cn[1].cn.push({
32742                 tag: 'p',
32743                 cls: 'masonry-brick-text',
32744                 html: this.html
32745             });
32746         }
32747
32748         if(this.bgimage.length){
32749             cfg.cn[0].cn.push({
32750                 tag: 'img',
32751                 cls: 'masonry-brick-image-view',
32752                 src: this.bgimage
32753             });
32754         }
32755         
32756         if(this.videourl.length){
32757             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32758             // youtube support only?
32759             cfg.cn[0].cn.cn.push({
32760                 tag: 'iframe',
32761                 cls: 'masonry-brick-image-view',
32762                 src: vurl,
32763                 frameborder : 0,
32764                 allowfullscreen : true
32765             });
32766         }
32767         
32768         return cfg;
32769     },
32770     
32771     initEvents: function() 
32772     {
32773         switch (this.size) {
32774             case 'xs' :
32775                 this.x = 1;
32776                 this.y = 1;
32777                 break;
32778             case 'sm' :
32779                 this.x = 2;
32780                 this.y = 2;
32781                 break;
32782             case 'md' :
32783             case 'md-left' :
32784             case 'md-right' :
32785                 this.x = 3;
32786                 this.y = 3;
32787                 break;
32788             case 'tall' :
32789                 this.x = 2;
32790                 this.y = 3;
32791                 break;
32792             case 'wide' :
32793                 this.x = 3;
32794                 this.y = 2;
32795                 break;
32796             case 'wide-thin' :
32797                 this.x = 3;
32798                 this.y = 1;
32799                 break;
32800                         
32801             default :
32802                 break;
32803         }
32804         
32805         if(Roo.isTouch){
32806             this.el.on('touchstart', this.onTouchStart, this);
32807             this.el.on('touchmove', this.onTouchMove, this);
32808             this.el.on('touchend', this.onTouchEnd, this);
32809             this.el.on('contextmenu', this.onContextMenu, this);
32810         } else {
32811             this.el.on('mouseenter'  ,this.enter, this);
32812             this.el.on('mouseleave', this.leave, this);
32813             this.el.on('click', this.onClick, this);
32814         }
32815         
32816         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32817             this.parent().bricks.push(this);   
32818         }
32819         
32820     },
32821     
32822     onClick: function(e, el)
32823     {
32824         var time = this.endTimer - this.startTimer;
32825         // Roo.log(e.preventDefault());
32826         if(Roo.isTouch){
32827             if(time > 1000){
32828                 e.preventDefault();
32829                 return;
32830             }
32831         }
32832         
32833         if(!this.preventDefault){
32834             return;
32835         }
32836         
32837         e.preventDefault();
32838         
32839         if (this.activeClass != '') {
32840             this.selectBrick();
32841         }
32842         
32843         this.fireEvent('click', this, e);
32844     },
32845     
32846     enter: function(e, el)
32847     {
32848         e.preventDefault();
32849         
32850         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32851             return;
32852         }
32853         
32854         if(this.bgimage.length && this.html.length){
32855             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32856         }
32857     },
32858     
32859     leave: function(e, el)
32860     {
32861         e.preventDefault();
32862         
32863         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32864             return;
32865         }
32866         
32867         if(this.bgimage.length && this.html.length){
32868             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32869         }
32870     },
32871     
32872     onTouchStart: function(e, el)
32873     {
32874 //        e.preventDefault();
32875         
32876         this.touchmoved = false;
32877         
32878         if(!this.isFitContainer){
32879             return;
32880         }
32881         
32882         if(!this.bgimage.length || !this.html.length){
32883             return;
32884         }
32885         
32886         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32887         
32888         this.timer = new Date().getTime();
32889         
32890     },
32891     
32892     onTouchMove: function(e, el)
32893     {
32894         this.touchmoved = true;
32895     },
32896     
32897     onContextMenu : function(e,el)
32898     {
32899         e.preventDefault();
32900         e.stopPropagation();
32901         return false;
32902     },
32903     
32904     onTouchEnd: function(e, el)
32905     {
32906 //        e.preventDefault();
32907         
32908         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32909         
32910             this.leave(e,el);
32911             
32912             return;
32913         }
32914         
32915         if(!this.bgimage.length || !this.html.length){
32916             
32917             if(this.href.length){
32918                 window.location.href = this.href;
32919             }
32920             
32921             return;
32922         }
32923         
32924         if(!this.isFitContainer){
32925             return;
32926         }
32927         
32928         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32929         
32930         window.location.href = this.href;
32931     },
32932     
32933     //selection on single brick only
32934     selectBrick : function() {
32935         
32936         if (!this.parentId) {
32937             return;
32938         }
32939         
32940         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32941         var index = m.selectedBrick.indexOf(this.id);
32942         
32943         if ( index > -1) {
32944             m.selectedBrick.splice(index,1);
32945             this.el.removeClass(this.activeClass);
32946             return;
32947         }
32948         
32949         for(var i = 0; i < m.selectedBrick.length; i++) {
32950             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32951             b.el.removeClass(b.activeClass);
32952         }
32953         
32954         m.selectedBrick = [];
32955         
32956         m.selectedBrick.push(this.id);
32957         this.el.addClass(this.activeClass);
32958         return;
32959     },
32960     
32961     isSelected : function(){
32962         return this.el.hasClass(this.activeClass);
32963         
32964     }
32965 });
32966
32967 Roo.apply(Roo.bootstrap.MasonryBrick, {
32968     
32969     //groups: {},
32970     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32971      /**
32972     * register a Masonry Brick
32973     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32974     */
32975     
32976     register : function(brick)
32977     {
32978         //this.groups[brick.id] = brick;
32979         this.groups.add(brick.id, brick);
32980     },
32981     /**
32982     * fetch a  masonry brick based on the masonry brick ID
32983     * @param {string} the masonry brick to add
32984     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32985     */
32986     
32987     get: function(brick_id) 
32988     {
32989         // if (typeof(this.groups[brick_id]) == 'undefined') {
32990         //     return false;
32991         // }
32992         // return this.groups[brick_id] ;
32993         
32994         if(this.groups.key(brick_id)) {
32995             return this.groups.key(brick_id);
32996         }
32997         
32998         return false;
32999     }
33000     
33001     
33002     
33003 });
33004
33005  /*
33006  * - LGPL
33007  *
33008  * element
33009  * 
33010  */
33011
33012 /**
33013  * @class Roo.bootstrap.Brick
33014  * @extends Roo.bootstrap.Component
33015  * Bootstrap Brick class
33016  * 
33017  * @constructor
33018  * Create a new Brick
33019  * @param {Object} config The config object
33020  */
33021
33022 Roo.bootstrap.Brick = function(config){
33023     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33024     
33025     this.addEvents({
33026         // raw events
33027         /**
33028          * @event click
33029          * When a Brick is click
33030          * @param {Roo.bootstrap.Brick} this
33031          * @param {Roo.EventObject} e
33032          */
33033         "click" : true
33034     });
33035 };
33036
33037 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
33038     
33039     /**
33040      * @cfg {String} title
33041      */   
33042     title : '',
33043     /**
33044      * @cfg {String} html
33045      */   
33046     html : '',
33047     /**
33048      * @cfg {String} bgimage
33049      */   
33050     bgimage : '',
33051     /**
33052      * @cfg {String} cls
33053      */   
33054     cls : '',
33055     /**
33056      * @cfg {String} href
33057      */   
33058     href : '',
33059     /**
33060      * @cfg {String} video
33061      */   
33062     video : '',
33063     /**
33064      * @cfg {Boolean} square
33065      */   
33066     square : true,
33067     
33068     getAutoCreate : function()
33069     {
33070         var cls = 'roo-brick';
33071         
33072         if(this.href.length){
33073             cls += ' roo-brick-link';
33074         }
33075         
33076         if(this.bgimage.length){
33077             cls += ' roo-brick-image';
33078         }
33079         
33080         if(!this.html.length && !this.bgimage.length){
33081             cls += ' roo-brick-center-title';
33082         }
33083         
33084         if(!this.html.length && this.bgimage.length){
33085             cls += ' roo-brick-bottom-title';
33086         }
33087         
33088         if(this.cls){
33089             cls += ' ' + this.cls;
33090         }
33091         
33092         var cfg = {
33093             tag: (this.href.length) ? 'a' : 'div',
33094             cls: cls,
33095             cn: [
33096                 {
33097                     tag: 'div',
33098                     cls: 'roo-brick-paragraph',
33099                     cn: []
33100                 }
33101             ]
33102         };
33103         
33104         if(this.href.length){
33105             cfg.href = this.href;
33106         }
33107         
33108         var cn = cfg.cn[0].cn;
33109         
33110         if(this.title.length){
33111             cn.push({
33112                 tag: 'h4',
33113                 cls: 'roo-brick-title',
33114                 html: this.title
33115             });
33116         }
33117         
33118         if(this.html.length){
33119             cn.push({
33120                 tag: 'p',
33121                 cls: 'roo-brick-text',
33122                 html: this.html
33123             });
33124         } else {
33125             cn.cls += ' hide';
33126         }
33127         
33128         if(this.bgimage.length){
33129             cfg.cn.push({
33130                 tag: 'img',
33131                 cls: 'roo-brick-image-view',
33132                 src: this.bgimage
33133             });
33134         }
33135         
33136         return cfg;
33137     },
33138     
33139     initEvents: function() 
33140     {
33141         if(this.title.length || this.html.length){
33142             this.el.on('mouseenter'  ,this.enter, this);
33143             this.el.on('mouseleave', this.leave, this);
33144         }
33145         
33146         Roo.EventManager.onWindowResize(this.resize, this); 
33147         
33148         if(this.bgimage.length){
33149             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33150             this.imageEl.on('load', this.onImageLoad, this);
33151             return;
33152         }
33153         
33154         this.resize();
33155     },
33156     
33157     onImageLoad : function()
33158     {
33159         this.resize();
33160     },
33161     
33162     resize : function()
33163     {
33164         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33165         
33166         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33167         
33168         if(this.bgimage.length){
33169             var image = this.el.select('.roo-brick-image-view', true).first();
33170             
33171             image.setWidth(paragraph.getWidth());
33172             
33173             if(this.square){
33174                 image.setHeight(paragraph.getWidth());
33175             }
33176             
33177             this.el.setHeight(image.getHeight());
33178             paragraph.setHeight(image.getHeight());
33179             
33180         }
33181         
33182     },
33183     
33184     enter: function(e, el)
33185     {
33186         e.preventDefault();
33187         
33188         if(this.bgimage.length){
33189             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33190             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33191         }
33192     },
33193     
33194     leave: function(e, el)
33195     {
33196         e.preventDefault();
33197         
33198         if(this.bgimage.length){
33199             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33200             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33201         }
33202     }
33203     
33204 });
33205
33206  
33207
33208  /*
33209  * - LGPL
33210  *
33211  * Number field 
33212  */
33213
33214 /**
33215  * @class Roo.bootstrap.NumberField
33216  * @extends Roo.bootstrap.Input
33217  * Bootstrap NumberField class
33218  * 
33219  * 
33220  * 
33221  * 
33222  * @constructor
33223  * Create a new NumberField
33224  * @param {Object} config The config object
33225  */
33226
33227 Roo.bootstrap.NumberField = function(config){
33228     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33229 };
33230
33231 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33232     
33233     /**
33234      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33235      */
33236     allowDecimals : true,
33237     /**
33238      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33239      */
33240     decimalSeparator : ".",
33241     /**
33242      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33243      */
33244     decimalPrecision : 2,
33245     /**
33246      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33247      */
33248     allowNegative : true,
33249     
33250     /**
33251      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33252      */
33253     allowZero: true,
33254     /**
33255      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33256      */
33257     minValue : Number.NEGATIVE_INFINITY,
33258     /**
33259      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33260      */
33261     maxValue : Number.MAX_VALUE,
33262     /**
33263      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33264      */
33265     minText : "The minimum value for this field is {0}",
33266     /**
33267      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33268      */
33269     maxText : "The maximum value for this field is {0}",
33270     /**
33271      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33272      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33273      */
33274     nanText : "{0} is not a valid number",
33275     /**
33276      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33277      */
33278     thousandsDelimiter : false,
33279     /**
33280      * @cfg {String} valueAlign alignment of value
33281      */
33282     valueAlign : "left",
33283
33284     getAutoCreate : function()
33285     {
33286         var hiddenInput = {
33287             tag: 'input',
33288             type: 'hidden',
33289             id: Roo.id(),
33290             cls: 'hidden-number-input'
33291         };
33292         
33293         if (this.name) {
33294             hiddenInput.name = this.name;
33295         }
33296         
33297         this.name = '';
33298         
33299         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33300         
33301         this.name = hiddenInput.name;
33302         
33303         if(cfg.cn.length > 0) {
33304             cfg.cn.push(hiddenInput);
33305         }
33306         
33307         return cfg;
33308     },
33309
33310     // private
33311     initEvents : function()
33312     {   
33313         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33314         
33315         var allowed = "0123456789";
33316         
33317         if(this.allowDecimals){
33318             allowed += this.decimalSeparator;
33319         }
33320         
33321         if(this.allowNegative){
33322             allowed += "-";
33323         }
33324         
33325         if(this.thousandsDelimiter) {
33326             allowed += ",";
33327         }
33328         
33329         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33330         
33331         var keyPress = function(e){
33332             
33333             var k = e.getKey();
33334             
33335             var c = e.getCharCode();
33336             
33337             if(
33338                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33339                     allowed.indexOf(String.fromCharCode(c)) === -1
33340             ){
33341                 e.stopEvent();
33342                 return;
33343             }
33344             
33345             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33346                 return;
33347             }
33348             
33349             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33350                 e.stopEvent();
33351             }
33352         };
33353         
33354         this.el.on("keypress", keyPress, this);
33355     },
33356     
33357     validateValue : function(value)
33358     {
33359         
33360         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33361             return false;
33362         }
33363         
33364         var num = this.parseValue(value);
33365         
33366         if(isNaN(num)){
33367             this.markInvalid(String.format(this.nanText, value));
33368             return false;
33369         }
33370         
33371         if(num < this.minValue){
33372             this.markInvalid(String.format(this.minText, this.minValue));
33373             return false;
33374         }
33375         
33376         if(num > this.maxValue){
33377             this.markInvalid(String.format(this.maxText, this.maxValue));
33378             return false;
33379         }
33380         
33381         return true;
33382     },
33383
33384     getValue : function()
33385     {
33386         var v = this.hiddenEl().getValue();
33387         
33388         return this.fixPrecision(this.parseValue(v));
33389     },
33390
33391     parseValue : function(value)
33392     {
33393         if(this.thousandsDelimiter) {
33394             value += "";
33395             r = new RegExp(",", "g");
33396             value = value.replace(r, "");
33397         }
33398         
33399         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33400         return isNaN(value) ? '' : value;
33401     },
33402
33403     fixPrecision : function(value)
33404     {
33405         if(this.thousandsDelimiter) {
33406             value += "";
33407             r = new RegExp(",", "g");
33408             value = value.replace(r, "");
33409         }
33410         
33411         var nan = isNaN(value);
33412         
33413         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33414             return nan ? '' : value;
33415         }
33416         return parseFloat(value).toFixed(this.decimalPrecision);
33417     },
33418
33419     setValue : function(v)
33420     {
33421         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33422         
33423         this.value = v;
33424         
33425         if(this.rendered){
33426             
33427             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33428             
33429             this.inputEl().dom.value = (v == '') ? '' :
33430                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33431             
33432             if(!this.allowZero && v === '0') {
33433                 this.hiddenEl().dom.value = '';
33434                 this.inputEl().dom.value = '';
33435             }
33436             
33437             this.validate();
33438         }
33439     },
33440
33441     decimalPrecisionFcn : function(v)
33442     {
33443         return Math.floor(v);
33444     },
33445
33446     beforeBlur : function()
33447     {
33448         var v = this.parseValue(this.getRawValue());
33449         
33450         if(v || v === 0 || v === ''){
33451             this.setValue(v);
33452         }
33453     },
33454     
33455     hiddenEl : function()
33456     {
33457         return this.el.select('input.hidden-number-input',true).first();
33458     }
33459     
33460 });
33461
33462  
33463
33464 /*
33465 * Licence: LGPL
33466 */
33467
33468 /**
33469  * @class Roo.bootstrap.DocumentSlider
33470  * @extends Roo.bootstrap.Component
33471  * Bootstrap DocumentSlider class
33472  * 
33473  * @constructor
33474  * Create a new DocumentViewer
33475  * @param {Object} config The config object
33476  */
33477
33478 Roo.bootstrap.DocumentSlider = function(config){
33479     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33480     
33481     this.files = [];
33482     
33483     this.addEvents({
33484         /**
33485          * @event initial
33486          * Fire after initEvent
33487          * @param {Roo.bootstrap.DocumentSlider} this
33488          */
33489         "initial" : true,
33490         /**
33491          * @event update
33492          * Fire after update
33493          * @param {Roo.bootstrap.DocumentSlider} this
33494          */
33495         "update" : true,
33496         /**
33497          * @event click
33498          * Fire after click
33499          * @param {Roo.bootstrap.DocumentSlider} this
33500          */
33501         "click" : true
33502     });
33503 };
33504
33505 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33506     
33507     files : false,
33508     
33509     indicator : 0,
33510     
33511     getAutoCreate : function()
33512     {
33513         var cfg = {
33514             tag : 'div',
33515             cls : 'roo-document-slider',
33516             cn : [
33517                 {
33518                     tag : 'div',
33519                     cls : 'roo-document-slider-header',
33520                     cn : [
33521                         {
33522                             tag : 'div',
33523                             cls : 'roo-document-slider-header-title'
33524                         }
33525                     ]
33526                 },
33527                 {
33528                     tag : 'div',
33529                     cls : 'roo-document-slider-body',
33530                     cn : [
33531                         {
33532                             tag : 'div',
33533                             cls : 'roo-document-slider-prev',
33534                             cn : [
33535                                 {
33536                                     tag : 'i',
33537                                     cls : 'fa fa-chevron-left'
33538                                 }
33539                             ]
33540                         },
33541                         {
33542                             tag : 'div',
33543                             cls : 'roo-document-slider-thumb',
33544                             cn : [
33545                                 {
33546                                     tag : 'img',
33547                                     cls : 'roo-document-slider-image'
33548                                 }
33549                             ]
33550                         },
33551                         {
33552                             tag : 'div',
33553                             cls : 'roo-document-slider-next',
33554                             cn : [
33555                                 {
33556                                     tag : 'i',
33557                                     cls : 'fa fa-chevron-right'
33558                                 }
33559                             ]
33560                         }
33561                     ]
33562                 }
33563             ]
33564         };
33565         
33566         return cfg;
33567     },
33568     
33569     initEvents : function()
33570     {
33571         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33572         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33573         
33574         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33575         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33576         
33577         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33578         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33579         
33580         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33581         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33582         
33583         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33584         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33585         
33586         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33587         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33588         
33589         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33590         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33591         
33592         this.thumbEl.on('click', this.onClick, this);
33593         
33594         this.prevIndicator.on('click', this.prev, this);
33595         
33596         this.nextIndicator.on('click', this.next, this);
33597         
33598     },
33599     
33600     initial : function()
33601     {
33602         if(this.files.length){
33603             this.indicator = 1;
33604             this.update()
33605         }
33606         
33607         this.fireEvent('initial', this);
33608     },
33609     
33610     update : function()
33611     {
33612         this.imageEl.attr('src', this.files[this.indicator - 1]);
33613         
33614         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33615         
33616         this.prevIndicator.show();
33617         
33618         if(this.indicator == 1){
33619             this.prevIndicator.hide();
33620         }
33621         
33622         this.nextIndicator.show();
33623         
33624         if(this.indicator == this.files.length){
33625             this.nextIndicator.hide();
33626         }
33627         
33628         this.thumbEl.scrollTo('top');
33629         
33630         this.fireEvent('update', this);
33631     },
33632     
33633     onClick : function(e)
33634     {
33635         e.preventDefault();
33636         
33637         this.fireEvent('click', this);
33638     },
33639     
33640     prev : function(e)
33641     {
33642         e.preventDefault();
33643         
33644         this.indicator = Math.max(1, this.indicator - 1);
33645         
33646         this.update();
33647     },
33648     
33649     next : function(e)
33650     {
33651         e.preventDefault();
33652         
33653         this.indicator = Math.min(this.files.length, this.indicator + 1);
33654         
33655         this.update();
33656     }
33657 });
33658 /*
33659  * - LGPL
33660  *
33661  * RadioSet
33662  *
33663  *
33664  */
33665
33666 /**
33667  * @class Roo.bootstrap.RadioSet
33668  * @extends Roo.bootstrap.Input
33669  * Bootstrap RadioSet class
33670  * @cfg {String} indicatorpos (left|right) default left
33671  * @cfg {Boolean} inline (true|false) inline the element (default true)
33672  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33673  * @constructor
33674  * Create a new RadioSet
33675  * @param {Object} config The config object
33676  */
33677
33678 Roo.bootstrap.RadioSet = function(config){
33679     
33680     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33681     
33682     this.radioes = [];
33683     
33684     Roo.bootstrap.RadioSet.register(this);
33685     
33686     this.addEvents({
33687         /**
33688         * @event check
33689         * Fires when the element is checked or unchecked.
33690         * @param {Roo.bootstrap.RadioSet} this This radio
33691         * @param {Roo.bootstrap.Radio} item The checked item
33692         */
33693        check : true,
33694        /**
33695         * @event click
33696         * Fires when the element is click.
33697         * @param {Roo.bootstrap.RadioSet} this This radio set
33698         * @param {Roo.bootstrap.Radio} item The checked item
33699         * @param {Roo.EventObject} e The event object
33700         */
33701        click : true
33702     });
33703     
33704 };
33705
33706 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33707
33708     radioes : false,
33709     
33710     inline : true,
33711     
33712     weight : '',
33713     
33714     indicatorpos : 'left',
33715     
33716     getAutoCreate : function()
33717     {
33718         var label = {
33719             tag : 'label',
33720             cls : 'roo-radio-set-label',
33721             cn : [
33722                 {
33723                     tag : 'span',
33724                     html : this.fieldLabel
33725                 }
33726             ]
33727         };
33728         
33729         if(this.indicatorpos == 'left'){
33730             label.cn.unshift({
33731                 tag : 'i',
33732                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33733                 tooltip : 'This field is required'
33734             });
33735         } else {
33736             label.cn.push({
33737                 tag : 'i',
33738                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33739                 tooltip : 'This field is required'
33740             });
33741         }
33742         
33743         var items = {
33744             tag : 'div',
33745             cls : 'roo-radio-set-items'
33746         };
33747         
33748         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33749         
33750         if (align === 'left' && this.fieldLabel.length) {
33751             
33752             items = {
33753                 cls : "roo-radio-set-right", 
33754                 cn: [
33755                     items
33756                 ]
33757             };
33758             
33759             if(this.labelWidth > 12){
33760                 label.style = "width: " + this.labelWidth + 'px';
33761             }
33762             
33763             if(this.labelWidth < 13 && this.labelmd == 0){
33764                 this.labelmd = this.labelWidth;
33765             }
33766             
33767             if(this.labellg > 0){
33768                 label.cls += ' col-lg-' + this.labellg;
33769                 items.cls += ' col-lg-' + (12 - this.labellg);
33770             }
33771             
33772             if(this.labelmd > 0){
33773                 label.cls += ' col-md-' + this.labelmd;
33774                 items.cls += ' col-md-' + (12 - this.labelmd);
33775             }
33776             
33777             if(this.labelsm > 0){
33778                 label.cls += ' col-sm-' + this.labelsm;
33779                 items.cls += ' col-sm-' + (12 - this.labelsm);
33780             }
33781             
33782             if(this.labelxs > 0){
33783                 label.cls += ' col-xs-' + this.labelxs;
33784                 items.cls += ' col-xs-' + (12 - this.labelxs);
33785             }
33786         }
33787         
33788         var cfg = {
33789             tag : 'div',
33790             cls : 'roo-radio-set',
33791             cn : [
33792                 {
33793                     tag : 'input',
33794                     cls : 'roo-radio-set-input',
33795                     type : 'hidden',
33796                     name : this.name,
33797                     value : this.value ? this.value :  ''
33798                 },
33799                 label,
33800                 items
33801             ]
33802         };
33803         
33804         if(this.weight.length){
33805             cfg.cls += ' roo-radio-' + this.weight;
33806         }
33807         
33808         if(this.inline) {
33809             cfg.cls += ' roo-radio-set-inline';
33810         }
33811         
33812         var settings=this;
33813         ['xs','sm','md','lg'].map(function(size){
33814             if (settings[size]) {
33815                 cfg.cls += ' col-' + size + '-' + settings[size];
33816             }
33817         });
33818         
33819         return cfg;
33820         
33821     },
33822
33823     initEvents : function()
33824     {
33825         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33826         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33827         
33828         if(!this.fieldLabel.length){
33829             this.labelEl.hide();
33830         }
33831         
33832         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33833         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33834         
33835         this.indicator = this.indicatorEl();
33836         
33837         if(this.indicator){
33838             this.indicator.addClass('invisible');
33839         }
33840         
33841         this.originalValue = this.getValue();
33842         
33843     },
33844     
33845     inputEl: function ()
33846     {
33847         return this.el.select('.roo-radio-set-input', true).first();
33848     },
33849     
33850     getChildContainer : function()
33851     {
33852         return this.itemsEl;
33853     },
33854     
33855     register : function(item)
33856     {
33857         this.radioes.push(item);
33858         
33859     },
33860     
33861     validate : function()
33862     {   
33863         if(this.getVisibilityEl().hasClass('hidden')){
33864             return true;
33865         }
33866         
33867         var valid = false;
33868         
33869         Roo.each(this.radioes, function(i){
33870             if(!i.checked){
33871                 return;
33872             }
33873             
33874             valid = true;
33875             return false;
33876         });
33877         
33878         if(this.allowBlank) {
33879             return true;
33880         }
33881         
33882         if(this.disabled || valid){
33883             this.markValid();
33884             return true;
33885         }
33886         
33887         this.markInvalid();
33888         return false;
33889         
33890     },
33891     
33892     markValid : function()
33893     {
33894         if(this.labelEl.isVisible(true)){
33895             this.indicatorEl().removeClass('visible');
33896             this.indicatorEl().addClass('invisible');
33897         }
33898         
33899         this.el.removeClass([this.invalidClass, this.validClass]);
33900         this.el.addClass(this.validClass);
33901         
33902         this.fireEvent('valid', this);
33903     },
33904     
33905     markInvalid : function(msg)
33906     {
33907         if(this.allowBlank || this.disabled){
33908             return;
33909         }
33910         
33911         if(this.labelEl.isVisible(true)){
33912             this.indicatorEl().removeClass('invisible');
33913             this.indicatorEl().addClass('visible');
33914         }
33915         
33916         this.el.removeClass([this.invalidClass, this.validClass]);
33917         this.el.addClass(this.invalidClass);
33918         
33919         this.fireEvent('invalid', this, msg);
33920         
33921     },
33922     
33923     setValue : function(v, suppressEvent)
33924     {   
33925         if(this.value === v){
33926             return;
33927         }
33928         
33929         this.value = v;
33930         
33931         if(this.rendered){
33932             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33933         }
33934         
33935         Roo.each(this.radioes, function(i){
33936             i.checked = false;
33937             i.el.removeClass('checked');
33938         });
33939         
33940         Roo.each(this.radioes, function(i){
33941             
33942             if(i.value === v || i.value.toString() === v.toString()){
33943                 i.checked = true;
33944                 i.el.addClass('checked');
33945                 
33946                 if(suppressEvent !== true){
33947                     this.fireEvent('check', this, i);
33948                 }
33949                 
33950                 return false;
33951             }
33952             
33953         }, this);
33954         
33955         this.validate();
33956     },
33957     
33958     clearInvalid : function(){
33959         
33960         if(!this.el || this.preventMark){
33961             return;
33962         }
33963         
33964         this.el.removeClass([this.invalidClass]);
33965         
33966         this.fireEvent('valid', this);
33967     }
33968     
33969 });
33970
33971 Roo.apply(Roo.bootstrap.RadioSet, {
33972     
33973     groups: {},
33974     
33975     register : function(set)
33976     {
33977         this.groups[set.name] = set;
33978     },
33979     
33980     get: function(name) 
33981     {
33982         if (typeof(this.groups[name]) == 'undefined') {
33983             return false;
33984         }
33985         
33986         return this.groups[name] ;
33987     }
33988     
33989 });
33990 /*
33991  * Based on:
33992  * Ext JS Library 1.1.1
33993  * Copyright(c) 2006-2007, Ext JS, LLC.
33994  *
33995  * Originally Released Under LGPL - original licence link has changed is not relivant.
33996  *
33997  * Fork - LGPL
33998  * <script type="text/javascript">
33999  */
34000
34001
34002 /**
34003  * @class Roo.bootstrap.SplitBar
34004  * @extends Roo.util.Observable
34005  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34006  * <br><br>
34007  * Usage:
34008  * <pre><code>
34009 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34010                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34011 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34012 split.minSize = 100;
34013 split.maxSize = 600;
34014 split.animate = true;
34015 split.on('moved', splitterMoved);
34016 </code></pre>
34017  * @constructor
34018  * Create a new SplitBar
34019  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
34020  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
34021  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34022  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
34023                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34024                         position of the SplitBar).
34025  */
34026 Roo.bootstrap.SplitBar = function(cfg){
34027     
34028     /** @private */
34029     
34030     //{
34031     //  dragElement : elm
34032     //  resizingElement: el,
34033         // optional..
34034     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34035     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
34036         // existingProxy ???
34037     //}
34038     
34039     this.el = Roo.get(cfg.dragElement, true);
34040     this.el.dom.unselectable = "on";
34041     /** @private */
34042     this.resizingEl = Roo.get(cfg.resizingElement, true);
34043
34044     /**
34045      * @private
34046      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34047      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34048      * @type Number
34049      */
34050     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34051     
34052     /**
34053      * The minimum size of the resizing element. (Defaults to 0)
34054      * @type Number
34055      */
34056     this.minSize = 0;
34057     
34058     /**
34059      * The maximum size of the resizing element. (Defaults to 2000)
34060      * @type Number
34061      */
34062     this.maxSize = 2000;
34063     
34064     /**
34065      * Whether to animate the transition to the new size
34066      * @type Boolean
34067      */
34068     this.animate = false;
34069     
34070     /**
34071      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34072      * @type Boolean
34073      */
34074     this.useShim = false;
34075     
34076     /** @private */
34077     this.shim = null;
34078     
34079     if(!cfg.existingProxy){
34080         /** @private */
34081         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34082     }else{
34083         this.proxy = Roo.get(cfg.existingProxy).dom;
34084     }
34085     /** @private */
34086     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34087     
34088     /** @private */
34089     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34090     
34091     /** @private */
34092     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34093     
34094     /** @private */
34095     this.dragSpecs = {};
34096     
34097     /**
34098      * @private The adapter to use to positon and resize elements
34099      */
34100     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34101     this.adapter.init(this);
34102     
34103     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34104         /** @private */
34105         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34106         this.el.addClass("roo-splitbar-h");
34107     }else{
34108         /** @private */
34109         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34110         this.el.addClass("roo-splitbar-v");
34111     }
34112     
34113     this.addEvents({
34114         /**
34115          * @event resize
34116          * Fires when the splitter is moved (alias for {@link #event-moved})
34117          * @param {Roo.bootstrap.SplitBar} this
34118          * @param {Number} newSize the new width or height
34119          */
34120         "resize" : true,
34121         /**
34122          * @event moved
34123          * Fires when the splitter is moved
34124          * @param {Roo.bootstrap.SplitBar} this
34125          * @param {Number} newSize the new width or height
34126          */
34127         "moved" : true,
34128         /**
34129          * @event beforeresize
34130          * Fires before the splitter is dragged
34131          * @param {Roo.bootstrap.SplitBar} this
34132          */
34133         "beforeresize" : true,
34134
34135         "beforeapply" : true
34136     });
34137
34138     Roo.util.Observable.call(this);
34139 };
34140
34141 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34142     onStartProxyDrag : function(x, y){
34143         this.fireEvent("beforeresize", this);
34144         if(!this.overlay){
34145             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
34146             o.unselectable();
34147             o.enableDisplayMode("block");
34148             // all splitbars share the same overlay
34149             Roo.bootstrap.SplitBar.prototype.overlay = o;
34150         }
34151         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34152         this.overlay.show();
34153         Roo.get(this.proxy).setDisplayed("block");
34154         var size = this.adapter.getElementSize(this);
34155         this.activeMinSize = this.getMinimumSize();;
34156         this.activeMaxSize = this.getMaximumSize();;
34157         var c1 = size - this.activeMinSize;
34158         var c2 = Math.max(this.activeMaxSize - size, 0);
34159         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34160             this.dd.resetConstraints();
34161             this.dd.setXConstraint(
34162                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
34163                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34164             );
34165             this.dd.setYConstraint(0, 0);
34166         }else{
34167             this.dd.resetConstraints();
34168             this.dd.setXConstraint(0, 0);
34169             this.dd.setYConstraint(
34170                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
34171                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34172             );
34173          }
34174         this.dragSpecs.startSize = size;
34175         this.dragSpecs.startPoint = [x, y];
34176         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34177     },
34178     
34179     /** 
34180      * @private Called after the drag operation by the DDProxy
34181      */
34182     onEndProxyDrag : function(e){
34183         Roo.get(this.proxy).setDisplayed(false);
34184         var endPoint = Roo.lib.Event.getXY(e);
34185         if(this.overlay){
34186             this.overlay.hide();
34187         }
34188         var newSize;
34189         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34190             newSize = this.dragSpecs.startSize + 
34191                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34192                     endPoint[0] - this.dragSpecs.startPoint[0] :
34193                     this.dragSpecs.startPoint[0] - endPoint[0]
34194                 );
34195         }else{
34196             newSize = this.dragSpecs.startSize + 
34197                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34198                     endPoint[1] - this.dragSpecs.startPoint[1] :
34199                     this.dragSpecs.startPoint[1] - endPoint[1]
34200                 );
34201         }
34202         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34203         if(newSize != this.dragSpecs.startSize){
34204             if(this.fireEvent('beforeapply', this, newSize) !== false){
34205                 this.adapter.setElementSize(this, newSize);
34206                 this.fireEvent("moved", this, newSize);
34207                 this.fireEvent("resize", this, newSize);
34208             }
34209         }
34210     },
34211     
34212     /**
34213      * Get the adapter this SplitBar uses
34214      * @return The adapter object
34215      */
34216     getAdapter : function(){
34217         return this.adapter;
34218     },
34219     
34220     /**
34221      * Set the adapter this SplitBar uses
34222      * @param {Object} adapter A SplitBar adapter object
34223      */
34224     setAdapter : function(adapter){
34225         this.adapter = adapter;
34226         this.adapter.init(this);
34227     },
34228     
34229     /**
34230      * Gets the minimum size for the resizing element
34231      * @return {Number} The minimum size
34232      */
34233     getMinimumSize : function(){
34234         return this.minSize;
34235     },
34236     
34237     /**
34238      * Sets the minimum size for the resizing element
34239      * @param {Number} minSize The minimum size
34240      */
34241     setMinimumSize : function(minSize){
34242         this.minSize = minSize;
34243     },
34244     
34245     /**
34246      * Gets the maximum size for the resizing element
34247      * @return {Number} The maximum size
34248      */
34249     getMaximumSize : function(){
34250         return this.maxSize;
34251     },
34252     
34253     /**
34254      * Sets the maximum size for the resizing element
34255      * @param {Number} maxSize The maximum size
34256      */
34257     setMaximumSize : function(maxSize){
34258         this.maxSize = maxSize;
34259     },
34260     
34261     /**
34262      * Sets the initialize size for the resizing element
34263      * @param {Number} size The initial size
34264      */
34265     setCurrentSize : function(size){
34266         var oldAnimate = this.animate;
34267         this.animate = false;
34268         this.adapter.setElementSize(this, size);
34269         this.animate = oldAnimate;
34270     },
34271     
34272     /**
34273      * Destroy this splitbar. 
34274      * @param {Boolean} removeEl True to remove the element
34275      */
34276     destroy : function(removeEl){
34277         if(this.shim){
34278             this.shim.remove();
34279         }
34280         this.dd.unreg();
34281         this.proxy.parentNode.removeChild(this.proxy);
34282         if(removeEl){
34283             this.el.remove();
34284         }
34285     }
34286 });
34287
34288 /**
34289  * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
34290  */
34291 Roo.bootstrap.SplitBar.createProxy = function(dir){
34292     var proxy = new Roo.Element(document.createElement("div"));
34293     proxy.unselectable();
34294     var cls = 'roo-splitbar-proxy';
34295     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34296     document.body.appendChild(proxy.dom);
34297     return proxy.dom;
34298 };
34299
34300 /** 
34301  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34302  * Default Adapter. It assumes the splitter and resizing element are not positioned
34303  * elements and only gets/sets the width of the element. Generally used for table based layouts.
34304  */
34305 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34306 };
34307
34308 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34309     // do nothing for now
34310     init : function(s){
34311     
34312     },
34313     /**
34314      * Called before drag operations to get the current size of the resizing element. 
34315      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34316      */
34317      getElementSize : function(s){
34318         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34319             return s.resizingEl.getWidth();
34320         }else{
34321             return s.resizingEl.getHeight();
34322         }
34323     },
34324     
34325     /**
34326      * Called after drag operations to set the size of the resizing element.
34327      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34328      * @param {Number} newSize The new size to set
34329      * @param {Function} onComplete A function to be invoked when resizing is complete
34330      */
34331     setElementSize : function(s, newSize, onComplete){
34332         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34333             if(!s.animate){
34334                 s.resizingEl.setWidth(newSize);
34335                 if(onComplete){
34336                     onComplete(s, newSize);
34337                 }
34338             }else{
34339                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34340             }
34341         }else{
34342             
34343             if(!s.animate){
34344                 s.resizingEl.setHeight(newSize);
34345                 if(onComplete){
34346                     onComplete(s, newSize);
34347                 }
34348             }else{
34349                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34350             }
34351         }
34352     }
34353 };
34354
34355 /** 
34356  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34357  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34358  * Adapter that  moves the splitter element to align with the resized sizing element. 
34359  * Used with an absolute positioned SplitBar.
34360  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34361  * document.body, make sure you assign an id to the body element.
34362  */
34363 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34364     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34365     this.container = Roo.get(container);
34366 };
34367
34368 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34369     init : function(s){
34370         this.basic.init(s);
34371     },
34372     
34373     getElementSize : function(s){
34374         return this.basic.getElementSize(s);
34375     },
34376     
34377     setElementSize : function(s, newSize, onComplete){
34378         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34379     },
34380     
34381     moveSplitter : function(s){
34382         var yes = Roo.bootstrap.SplitBar;
34383         switch(s.placement){
34384             case yes.LEFT:
34385                 s.el.setX(s.resizingEl.getRight());
34386                 break;
34387             case yes.RIGHT:
34388                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34389                 break;
34390             case yes.TOP:
34391                 s.el.setY(s.resizingEl.getBottom());
34392                 break;
34393             case yes.BOTTOM:
34394                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34395                 break;
34396         }
34397     }
34398 };
34399
34400 /**
34401  * Orientation constant - Create a vertical SplitBar
34402  * @static
34403  * @type Number
34404  */
34405 Roo.bootstrap.SplitBar.VERTICAL = 1;
34406
34407 /**
34408  * Orientation constant - Create a horizontal SplitBar
34409  * @static
34410  * @type Number
34411  */
34412 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34413
34414 /**
34415  * Placement constant - The resizing element is to the left of the splitter element
34416  * @static
34417  * @type Number
34418  */
34419 Roo.bootstrap.SplitBar.LEFT = 1;
34420
34421 /**
34422  * Placement constant - The resizing element is to the right of the splitter element
34423  * @static
34424  * @type Number
34425  */
34426 Roo.bootstrap.SplitBar.RIGHT = 2;
34427
34428 /**
34429  * Placement constant - The resizing element is positioned above the splitter element
34430  * @static
34431  * @type Number
34432  */
34433 Roo.bootstrap.SplitBar.TOP = 3;
34434
34435 /**
34436  * Placement constant - The resizing element is positioned under splitter element
34437  * @static
34438  * @type Number
34439  */
34440 Roo.bootstrap.SplitBar.BOTTOM = 4;
34441 Roo.namespace("Roo.bootstrap.layout");/*
34442  * Based on:
34443  * Ext JS Library 1.1.1
34444  * Copyright(c) 2006-2007, Ext JS, LLC.
34445  *
34446  * Originally Released Under LGPL - original licence link has changed is not relivant.
34447  *
34448  * Fork - LGPL
34449  * <script type="text/javascript">
34450  */
34451
34452 /**
34453  * @class Roo.bootstrap.layout.Manager
34454  * @extends Roo.bootstrap.Component
34455  * Base class for layout managers.
34456  */
34457 Roo.bootstrap.layout.Manager = function(config)
34458 {
34459     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34460
34461
34462
34463
34464
34465     /** false to disable window resize monitoring @type Boolean */
34466     this.monitorWindowResize = true;
34467     this.regions = {};
34468     this.addEvents({
34469         /**
34470          * @event layout
34471          * Fires when a layout is performed.
34472          * @param {Roo.LayoutManager} this
34473          */
34474         "layout" : true,
34475         /**
34476          * @event regionresized
34477          * Fires when the user resizes a region.
34478          * @param {Roo.LayoutRegion} region The resized region
34479          * @param {Number} newSize The new size (width for east/west, height for north/south)
34480          */
34481         "regionresized" : true,
34482         /**
34483          * @event regioncollapsed
34484          * Fires when a region is collapsed.
34485          * @param {Roo.LayoutRegion} region The collapsed region
34486          */
34487         "regioncollapsed" : true,
34488         /**
34489          * @event regionexpanded
34490          * Fires when a region is expanded.
34491          * @param {Roo.LayoutRegion} region The expanded region
34492          */
34493         "regionexpanded" : true
34494     });
34495     this.updating = false;
34496
34497     if (config.el) {
34498         this.el = Roo.get(config.el);
34499         this.initEvents();
34500     }
34501
34502 };
34503
34504 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34505
34506
34507     regions : null,
34508
34509     monitorWindowResize : true,
34510
34511
34512     updating : false,
34513
34514
34515     onRender : function(ct, position)
34516     {
34517         if(!this.el){
34518             this.el = Roo.get(ct);
34519             this.initEvents();
34520         }
34521         //this.fireEvent('render',this);
34522     },
34523
34524
34525     initEvents: function()
34526     {
34527
34528
34529         // ie scrollbar fix
34530         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34531             document.body.scroll = "no";
34532         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34533             this.el.position('relative');
34534         }
34535         this.id = this.el.id;
34536         this.el.addClass("roo-layout-container");
34537         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34538         if(this.el.dom != document.body ) {
34539             this.el.on('resize', this.layout,this);
34540             this.el.on('show', this.layout,this);
34541         }
34542
34543     },
34544
34545     /**
34546      * Returns true if this layout is currently being updated
34547      * @return {Boolean}
34548      */
34549     isUpdating : function(){
34550         return this.updating;
34551     },
34552
34553     /**
34554      * Suspend the LayoutManager from doing auto-layouts while
34555      * making multiple add or remove calls
34556      */
34557     beginUpdate : function(){
34558         this.updating = true;
34559     },
34560
34561     /**
34562      * Restore auto-layouts and optionally disable the manager from performing a layout
34563      * @param {Boolean} noLayout true to disable a layout update
34564      */
34565     endUpdate : function(noLayout){
34566         this.updating = false;
34567         if(!noLayout){
34568             this.layout();
34569         }
34570     },
34571
34572     layout: function(){
34573         // abstract...
34574     },
34575
34576     onRegionResized : function(region, newSize){
34577         this.fireEvent("regionresized", region, newSize);
34578         this.layout();
34579     },
34580
34581     onRegionCollapsed : function(region){
34582         this.fireEvent("regioncollapsed", region);
34583     },
34584
34585     onRegionExpanded : function(region){
34586         this.fireEvent("regionexpanded", region);
34587     },
34588
34589     /**
34590      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34591      * performs box-model adjustments.
34592      * @return {Object} The size as an object {width: (the width), height: (the height)}
34593      */
34594     getViewSize : function()
34595     {
34596         var size;
34597         if(this.el.dom != document.body){
34598             size = this.el.getSize();
34599         }else{
34600             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34601         }
34602         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34603         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34604         return size;
34605     },
34606
34607     /**
34608      * Returns the Element this layout is bound to.
34609      * @return {Roo.Element}
34610      */
34611     getEl : function(){
34612         return this.el;
34613     },
34614
34615     /**
34616      * Returns the specified region.
34617      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34618      * @return {Roo.LayoutRegion}
34619      */
34620     getRegion : function(target){
34621         return this.regions[target.toLowerCase()];
34622     },
34623
34624     onWindowResize : function(){
34625         if(this.monitorWindowResize){
34626             this.layout();
34627         }
34628     }
34629 });
34630 /*
34631  * Based on:
34632  * Ext JS Library 1.1.1
34633  * Copyright(c) 2006-2007, Ext JS, LLC.
34634  *
34635  * Originally Released Under LGPL - original licence link has changed is not relivant.
34636  *
34637  * Fork - LGPL
34638  * <script type="text/javascript">
34639  */
34640 /**
34641  * @class Roo.bootstrap.layout.Border
34642  * @extends Roo.bootstrap.layout.Manager
34643  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34644  * please see: examples/bootstrap/nested.html<br><br>
34645  
34646 <b>The container the layout is rendered into can be either the body element or any other element.
34647 If it is not the body element, the container needs to either be an absolute positioned element,
34648 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34649 the container size if it is not the body element.</b>
34650
34651 * @constructor
34652 * Create a new Border
34653 * @param {Object} config Configuration options
34654  */
34655 Roo.bootstrap.layout.Border = function(config){
34656     config = config || {};
34657     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34658     
34659     
34660     
34661     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34662         if(config[region]){
34663             config[region].region = region;
34664             this.addRegion(config[region]);
34665         }
34666     },this);
34667     
34668 };
34669
34670 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34671
34672 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34673     /**
34674      * Creates and adds a new region if it doesn't already exist.
34675      * @param {String} target The target region key (north, south, east, west or center).
34676      * @param {Object} config The regions config object
34677      * @return {BorderLayoutRegion} The new region
34678      */
34679     addRegion : function(config)
34680     {
34681         if(!this.regions[config.region]){
34682             var r = this.factory(config);
34683             this.bindRegion(r);
34684         }
34685         return this.regions[config.region];
34686     },
34687
34688     // private (kinda)
34689     bindRegion : function(r){
34690         this.regions[r.config.region] = r;
34691         
34692         r.on("visibilitychange",    this.layout, this);
34693         r.on("paneladded",          this.layout, this);
34694         r.on("panelremoved",        this.layout, this);
34695         r.on("invalidated",         this.layout, this);
34696         r.on("resized",             this.onRegionResized, this);
34697         r.on("collapsed",           this.onRegionCollapsed, this);
34698         r.on("expanded",            this.onRegionExpanded, this);
34699     },
34700
34701     /**
34702      * Performs a layout update.
34703      */
34704     layout : function()
34705     {
34706         if(this.updating) {
34707             return;
34708         }
34709         
34710         // render all the rebions if they have not been done alreayd?
34711         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34712             if(this.regions[region] && !this.regions[region].bodyEl){
34713                 this.regions[region].onRender(this.el)
34714             }
34715         },this);
34716         
34717         var size = this.getViewSize();
34718         var w = size.width;
34719         var h = size.height;
34720         var centerW = w;
34721         var centerH = h;
34722         var centerY = 0;
34723         var centerX = 0;
34724         //var x = 0, y = 0;
34725
34726         var rs = this.regions;
34727         var north = rs["north"];
34728         var south = rs["south"]; 
34729         var west = rs["west"];
34730         var east = rs["east"];
34731         var center = rs["center"];
34732         //if(this.hideOnLayout){ // not supported anymore
34733             //c.el.setStyle("display", "none");
34734         //}
34735         if(north && north.isVisible()){
34736             var b = north.getBox();
34737             var m = north.getMargins();
34738             b.width = w - (m.left+m.right);
34739             b.x = m.left;
34740             b.y = m.top;
34741             centerY = b.height + b.y + m.bottom;
34742             centerH -= centerY;
34743             north.updateBox(this.safeBox(b));
34744         }
34745         if(south && south.isVisible()){
34746             var b = south.getBox();
34747             var m = south.getMargins();
34748             b.width = w - (m.left+m.right);
34749             b.x = m.left;
34750             var totalHeight = (b.height + m.top + m.bottom);
34751             b.y = h - totalHeight + m.top;
34752             centerH -= totalHeight;
34753             south.updateBox(this.safeBox(b));
34754         }
34755         if(west && west.isVisible()){
34756             var b = west.getBox();
34757             var m = west.getMargins();
34758             b.height = centerH - (m.top+m.bottom);
34759             b.x = m.left;
34760             b.y = centerY + m.top;
34761             var totalWidth = (b.width + m.left + m.right);
34762             centerX += totalWidth;
34763             centerW -= totalWidth;
34764             west.updateBox(this.safeBox(b));
34765         }
34766         if(east && east.isVisible()){
34767             var b = east.getBox();
34768             var m = east.getMargins();
34769             b.height = centerH - (m.top+m.bottom);
34770             var totalWidth = (b.width + m.left + m.right);
34771             b.x = w - totalWidth + m.left;
34772             b.y = centerY + m.top;
34773             centerW -= totalWidth;
34774             east.updateBox(this.safeBox(b));
34775         }
34776         if(center){
34777             var m = center.getMargins();
34778             var centerBox = {
34779                 x: centerX + m.left,
34780                 y: centerY + m.top,
34781                 width: centerW - (m.left+m.right),
34782                 height: centerH - (m.top+m.bottom)
34783             };
34784             //if(this.hideOnLayout){
34785                 //center.el.setStyle("display", "block");
34786             //}
34787             center.updateBox(this.safeBox(centerBox));
34788         }
34789         this.el.repaint();
34790         this.fireEvent("layout", this);
34791     },
34792
34793     // private
34794     safeBox : function(box){
34795         box.width = Math.max(0, box.width);
34796         box.height = Math.max(0, box.height);
34797         return box;
34798     },
34799
34800     /**
34801      * Adds a ContentPanel (or subclass) to this layout.
34802      * @param {String} target The target region key (north, south, east, west or center).
34803      * @param {Roo.ContentPanel} panel The panel to add
34804      * @return {Roo.ContentPanel} The added panel
34805      */
34806     add : function(target, panel){
34807          
34808         target = target.toLowerCase();
34809         return this.regions[target].add(panel);
34810     },
34811
34812     /**
34813      * Remove a ContentPanel (or subclass) to this layout.
34814      * @param {String} target The target region key (north, south, east, west or center).
34815      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34816      * @return {Roo.ContentPanel} The removed panel
34817      */
34818     remove : function(target, panel){
34819         target = target.toLowerCase();
34820         return this.regions[target].remove(panel);
34821     },
34822
34823     /**
34824      * Searches all regions for a panel with the specified id
34825      * @param {String} panelId
34826      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34827      */
34828     findPanel : function(panelId){
34829         var rs = this.regions;
34830         for(var target in rs){
34831             if(typeof rs[target] != "function"){
34832                 var p = rs[target].getPanel(panelId);
34833                 if(p){
34834                     return p;
34835                 }
34836             }
34837         }
34838         return null;
34839     },
34840
34841     /**
34842      * Searches all regions for a panel with the specified id and activates (shows) it.
34843      * @param {String/ContentPanel} panelId The panels id or the panel itself
34844      * @return {Roo.ContentPanel} The shown panel or null
34845      */
34846     showPanel : function(panelId) {
34847       var rs = this.regions;
34848       for(var target in rs){
34849          var r = rs[target];
34850          if(typeof r != "function"){
34851             if(r.hasPanel(panelId)){
34852                return r.showPanel(panelId);
34853             }
34854          }
34855       }
34856       return null;
34857    },
34858
34859    /**
34860      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34861      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34862      */
34863    /*
34864     restoreState : function(provider){
34865         if(!provider){
34866             provider = Roo.state.Manager;
34867         }
34868         var sm = new Roo.LayoutStateManager();
34869         sm.init(this, provider);
34870     },
34871 */
34872  
34873  
34874     /**
34875      * Adds a xtype elements to the layout.
34876      * <pre><code>
34877
34878 layout.addxtype({
34879        xtype : 'ContentPanel',
34880        region: 'west',
34881        items: [ .... ]
34882    }
34883 );
34884
34885 layout.addxtype({
34886         xtype : 'NestedLayoutPanel',
34887         region: 'west',
34888         layout: {
34889            center: { },
34890            west: { }   
34891         },
34892         items : [ ... list of content panels or nested layout panels.. ]
34893    }
34894 );
34895 </code></pre>
34896      * @param {Object} cfg Xtype definition of item to add.
34897      */
34898     addxtype : function(cfg)
34899     {
34900         // basically accepts a pannel...
34901         // can accept a layout region..!?!?
34902         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34903         
34904         
34905         // theory?  children can only be panels??
34906         
34907         //if (!cfg.xtype.match(/Panel$/)) {
34908         //    return false;
34909         //}
34910         var ret = false;
34911         
34912         if (typeof(cfg.region) == 'undefined') {
34913             Roo.log("Failed to add Panel, region was not set");
34914             Roo.log(cfg);
34915             return false;
34916         }
34917         var region = cfg.region;
34918         delete cfg.region;
34919         
34920           
34921         var xitems = [];
34922         if (cfg.items) {
34923             xitems = cfg.items;
34924             delete cfg.items;
34925         }
34926         var nb = false;
34927         
34928         switch(cfg.xtype) 
34929         {
34930             case 'Content':  // ContentPanel (el, cfg)
34931             case 'Scroll':  // ContentPanel (el, cfg)
34932             case 'View': 
34933                 cfg.autoCreate = true;
34934                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34935                 //} else {
34936                 //    var el = this.el.createChild();
34937                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34938                 //}
34939                 
34940                 this.add(region, ret);
34941                 break;
34942             
34943             /*
34944             case 'TreePanel': // our new panel!
34945                 cfg.el = this.el.createChild();
34946                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34947                 this.add(region, ret);
34948                 break;
34949             */
34950             
34951             case 'Nest': 
34952                 // create a new Layout (which is  a Border Layout...
34953                 
34954                 var clayout = cfg.layout;
34955                 clayout.el  = this.el.createChild();
34956                 clayout.items   = clayout.items  || [];
34957                 
34958                 delete cfg.layout;
34959                 
34960                 // replace this exitems with the clayout ones..
34961                 xitems = clayout.items;
34962                  
34963                 // force background off if it's in center...
34964                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34965                     cfg.background = false;
34966                 }
34967                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34968                 
34969                 
34970                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34971                 //console.log('adding nested layout panel '  + cfg.toSource());
34972                 this.add(region, ret);
34973                 nb = {}; /// find first...
34974                 break;
34975             
34976             case 'Grid':
34977                 
34978                 // needs grid and region
34979                 
34980                 //var el = this.getRegion(region).el.createChild();
34981                 /*
34982                  *var el = this.el.createChild();
34983                 // create the grid first...
34984                 cfg.grid.container = el;
34985                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34986                 */
34987                 
34988                 if (region == 'center' && this.active ) {
34989                     cfg.background = false;
34990                 }
34991                 
34992                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34993                 
34994                 this.add(region, ret);
34995                 /*
34996                 if (cfg.background) {
34997                     // render grid on panel activation (if panel background)
34998                     ret.on('activate', function(gp) {
34999                         if (!gp.grid.rendered) {
35000                     //        gp.grid.render(el);
35001                         }
35002                     });
35003                 } else {
35004                   //  cfg.grid.render(el);
35005                 }
35006                 */
35007                 break;
35008            
35009            
35010             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35011                 // it was the old xcomponent building that caused this before.
35012                 // espeically if border is the top element in the tree.
35013                 ret = this;
35014                 break; 
35015                 
35016                     
35017                 
35018                 
35019                 
35020             default:
35021                 /*
35022                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35023                     
35024                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35025                     this.add(region, ret);
35026                 } else {
35027                 */
35028                     Roo.log(cfg);
35029                     throw "Can not add '" + cfg.xtype + "' to Border";
35030                     return null;
35031              
35032                                 
35033              
35034         }
35035         this.beginUpdate();
35036         // add children..
35037         var region = '';
35038         var abn = {};
35039         Roo.each(xitems, function(i)  {
35040             region = nb && i.region ? i.region : false;
35041             
35042             var add = ret.addxtype(i);
35043            
35044             if (region) {
35045                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35046                 if (!i.background) {
35047                     abn[region] = nb[region] ;
35048                 }
35049             }
35050             
35051         });
35052         this.endUpdate();
35053
35054         // make the last non-background panel active..
35055         //if (nb) { Roo.log(abn); }
35056         if (nb) {
35057             
35058             for(var r in abn) {
35059                 region = this.getRegion(r);
35060                 if (region) {
35061                     // tried using nb[r], but it does not work..
35062                      
35063                     region.showPanel(abn[r]);
35064                    
35065                 }
35066             }
35067         }
35068         return ret;
35069         
35070     },
35071     
35072     
35073 // private
35074     factory : function(cfg)
35075     {
35076         
35077         var validRegions = Roo.bootstrap.layout.Border.regions;
35078
35079         var target = cfg.region;
35080         cfg.mgr = this;
35081         
35082         var r = Roo.bootstrap.layout;
35083         Roo.log(target);
35084         switch(target){
35085             case "north":
35086                 return new r.North(cfg);
35087             case "south":
35088                 return new r.South(cfg);
35089             case "east":
35090                 return new r.East(cfg);
35091             case "west":
35092                 return new r.West(cfg);
35093             case "center":
35094                 return new r.Center(cfg);
35095         }
35096         throw 'Layout region "'+target+'" not supported.';
35097     }
35098     
35099     
35100 });
35101  /*
35102  * Based on:
35103  * Ext JS Library 1.1.1
35104  * Copyright(c) 2006-2007, Ext JS, LLC.
35105  *
35106  * Originally Released Under LGPL - original licence link has changed is not relivant.
35107  *
35108  * Fork - LGPL
35109  * <script type="text/javascript">
35110  */
35111  
35112 /**
35113  * @class Roo.bootstrap.layout.Basic
35114  * @extends Roo.util.Observable
35115  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35116  * and does not have a titlebar, tabs or any other features. All it does is size and position 
35117  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35118  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35119  * @cfg {string}   region  the region that it inhabits..
35120  * @cfg {bool}   skipConfig skip config?
35121  * 
35122
35123  */
35124 Roo.bootstrap.layout.Basic = function(config){
35125     
35126     this.mgr = config.mgr;
35127     
35128     this.position = config.region;
35129     
35130     var skipConfig = config.skipConfig;
35131     
35132     this.events = {
35133         /**
35134          * @scope Roo.BasicLayoutRegion
35135          */
35136         
35137         /**
35138          * @event beforeremove
35139          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35140          * @param {Roo.LayoutRegion} this
35141          * @param {Roo.ContentPanel} panel The panel
35142          * @param {Object} e The cancel event object
35143          */
35144         "beforeremove" : true,
35145         /**
35146          * @event invalidated
35147          * Fires when the layout for this region is changed.
35148          * @param {Roo.LayoutRegion} this
35149          */
35150         "invalidated" : true,
35151         /**
35152          * @event visibilitychange
35153          * Fires when this region is shown or hidden 
35154          * @param {Roo.LayoutRegion} this
35155          * @param {Boolean} visibility true or false
35156          */
35157         "visibilitychange" : true,
35158         /**
35159          * @event paneladded
35160          * Fires when a panel is added. 
35161          * @param {Roo.LayoutRegion} this
35162          * @param {Roo.ContentPanel} panel The panel
35163          */
35164         "paneladded" : true,
35165         /**
35166          * @event panelremoved
35167          * Fires when a panel is removed. 
35168          * @param {Roo.LayoutRegion} this
35169          * @param {Roo.ContentPanel} panel The panel
35170          */
35171         "panelremoved" : true,
35172         /**
35173          * @event beforecollapse
35174          * Fires when this region before collapse.
35175          * @param {Roo.LayoutRegion} this
35176          */
35177         "beforecollapse" : true,
35178         /**
35179          * @event collapsed
35180          * Fires when this region is collapsed.
35181          * @param {Roo.LayoutRegion} this
35182          */
35183         "collapsed" : true,
35184         /**
35185          * @event expanded
35186          * Fires when this region is expanded.
35187          * @param {Roo.LayoutRegion} this
35188          */
35189         "expanded" : true,
35190         /**
35191          * @event slideshow
35192          * Fires when this region is slid into view.
35193          * @param {Roo.LayoutRegion} this
35194          */
35195         "slideshow" : true,
35196         /**
35197          * @event slidehide
35198          * Fires when this region slides out of view. 
35199          * @param {Roo.LayoutRegion} this
35200          */
35201         "slidehide" : true,
35202         /**
35203          * @event panelactivated
35204          * Fires when a panel is activated. 
35205          * @param {Roo.LayoutRegion} this
35206          * @param {Roo.ContentPanel} panel The activated panel
35207          */
35208         "panelactivated" : true,
35209         /**
35210          * @event resized
35211          * Fires when the user resizes this region. 
35212          * @param {Roo.LayoutRegion} this
35213          * @param {Number} newSize The new size (width for east/west, height for north/south)
35214          */
35215         "resized" : true
35216     };
35217     /** A collection of panels in this region. @type Roo.util.MixedCollection */
35218     this.panels = new Roo.util.MixedCollection();
35219     this.panels.getKey = this.getPanelId.createDelegate(this);
35220     this.box = null;
35221     this.activePanel = null;
35222     // ensure listeners are added...
35223     
35224     if (config.listeners || config.events) {
35225         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35226             listeners : config.listeners || {},
35227             events : config.events || {}
35228         });
35229     }
35230     
35231     if(skipConfig !== true){
35232         this.applyConfig(config);
35233     }
35234 };
35235
35236 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35237 {
35238     getPanelId : function(p){
35239         return p.getId();
35240     },
35241     
35242     applyConfig : function(config){
35243         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35244         this.config = config;
35245         
35246     },
35247     
35248     /**
35249      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
35250      * the width, for horizontal (north, south) the height.
35251      * @param {Number} newSize The new width or height
35252      */
35253     resizeTo : function(newSize){
35254         var el = this.el ? this.el :
35255                  (this.activePanel ? this.activePanel.getEl() : null);
35256         if(el){
35257             switch(this.position){
35258                 case "east":
35259                 case "west":
35260                     el.setWidth(newSize);
35261                     this.fireEvent("resized", this, newSize);
35262                 break;
35263                 case "north":
35264                 case "south":
35265                     el.setHeight(newSize);
35266                     this.fireEvent("resized", this, newSize);
35267                 break;                
35268             }
35269         }
35270     },
35271     
35272     getBox : function(){
35273         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35274     },
35275     
35276     getMargins : function(){
35277         return this.margins;
35278     },
35279     
35280     updateBox : function(box){
35281         this.box = box;
35282         var el = this.activePanel.getEl();
35283         el.dom.style.left = box.x + "px";
35284         el.dom.style.top = box.y + "px";
35285         this.activePanel.setSize(box.width, box.height);
35286     },
35287     
35288     /**
35289      * Returns the container element for this region.
35290      * @return {Roo.Element}
35291      */
35292     getEl : function(){
35293         return this.activePanel;
35294     },
35295     
35296     /**
35297      * Returns true if this region is currently visible.
35298      * @return {Boolean}
35299      */
35300     isVisible : function(){
35301         return this.activePanel ? true : false;
35302     },
35303     
35304     setActivePanel : function(panel){
35305         panel = this.getPanel(panel);
35306         if(this.activePanel && this.activePanel != panel){
35307             this.activePanel.setActiveState(false);
35308             this.activePanel.getEl().setLeftTop(-10000,-10000);
35309         }
35310         this.activePanel = panel;
35311         panel.setActiveState(true);
35312         if(this.box){
35313             panel.setSize(this.box.width, this.box.height);
35314         }
35315         this.fireEvent("panelactivated", this, panel);
35316         this.fireEvent("invalidated");
35317     },
35318     
35319     /**
35320      * Show the specified panel.
35321      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35322      * @return {Roo.ContentPanel} The shown panel or null
35323      */
35324     showPanel : function(panel){
35325         panel = this.getPanel(panel);
35326         if(panel){
35327             this.setActivePanel(panel);
35328         }
35329         return panel;
35330     },
35331     
35332     /**
35333      * Get the active panel for this region.
35334      * @return {Roo.ContentPanel} The active panel or null
35335      */
35336     getActivePanel : function(){
35337         return this.activePanel;
35338     },
35339     
35340     /**
35341      * Add the passed ContentPanel(s)
35342      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35343      * @return {Roo.ContentPanel} The panel added (if only one was added)
35344      */
35345     add : function(panel){
35346         if(arguments.length > 1){
35347             for(var i = 0, len = arguments.length; i < len; i++) {
35348                 this.add(arguments[i]);
35349             }
35350             return null;
35351         }
35352         if(this.hasPanel(panel)){
35353             this.showPanel(panel);
35354             return panel;
35355         }
35356         var el = panel.getEl();
35357         if(el.dom.parentNode != this.mgr.el.dom){
35358             this.mgr.el.dom.appendChild(el.dom);
35359         }
35360         if(panel.setRegion){
35361             panel.setRegion(this);
35362         }
35363         this.panels.add(panel);
35364         el.setStyle("position", "absolute");
35365         if(!panel.background){
35366             this.setActivePanel(panel);
35367             if(this.config.initialSize && this.panels.getCount()==1){
35368                 this.resizeTo(this.config.initialSize);
35369             }
35370         }
35371         this.fireEvent("paneladded", this, panel);
35372         return panel;
35373     },
35374     
35375     /**
35376      * Returns true if the panel is in this region.
35377      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35378      * @return {Boolean}
35379      */
35380     hasPanel : function(panel){
35381         if(typeof panel == "object"){ // must be panel obj
35382             panel = panel.getId();
35383         }
35384         return this.getPanel(panel) ? true : false;
35385     },
35386     
35387     /**
35388      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35389      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35390      * @param {Boolean} preservePanel Overrides the config preservePanel option
35391      * @return {Roo.ContentPanel} The panel that was removed
35392      */
35393     remove : function(panel, preservePanel){
35394         panel = this.getPanel(panel);
35395         if(!panel){
35396             return null;
35397         }
35398         var e = {};
35399         this.fireEvent("beforeremove", this, panel, e);
35400         if(e.cancel === true){
35401             return null;
35402         }
35403         var panelId = panel.getId();
35404         this.panels.removeKey(panelId);
35405         return panel;
35406     },
35407     
35408     /**
35409      * Returns the panel specified or null if it's not in this region.
35410      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35411      * @return {Roo.ContentPanel}
35412      */
35413     getPanel : function(id){
35414         if(typeof id == "object"){ // must be panel obj
35415             return id;
35416         }
35417         return this.panels.get(id);
35418     },
35419     
35420     /**
35421      * Returns this regions position (north/south/east/west/center).
35422      * @return {String} 
35423      */
35424     getPosition: function(){
35425         return this.position;    
35426     }
35427 });/*
35428  * Based on:
35429  * Ext JS Library 1.1.1
35430  * Copyright(c) 2006-2007, Ext JS, LLC.
35431  *
35432  * Originally Released Under LGPL - original licence link has changed is not relivant.
35433  *
35434  * Fork - LGPL
35435  * <script type="text/javascript">
35436  */
35437  
35438 /**
35439  * @class Roo.bootstrap.layout.Region
35440  * @extends Roo.bootstrap.layout.Basic
35441  * This class represents a region in a layout manager.
35442  
35443  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35444  * @cfg {Object}    cmargins        Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
35445  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35446  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35447  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35448  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35449  * @cfg {String}    title           The title for the region (overrides panel titles)
35450  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35451  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35452  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35453  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35454  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35455  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35456  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35457  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35458  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35459  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35460
35461  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35462  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35463  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35464  * @cfg {Number}    width           For East/West panels
35465  * @cfg {Number}    height          For North/South panels
35466  * @cfg {Boolean}   split           To show the splitter
35467  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35468  * 
35469  * @cfg {string}   cls             Extra CSS classes to add to region
35470  * 
35471  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35472  * @cfg {string}   region  the region that it inhabits..
35473  *
35474
35475  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35476  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35477
35478  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35479  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35480  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35481  */
35482 Roo.bootstrap.layout.Region = function(config)
35483 {
35484     this.applyConfig(config);
35485
35486     var mgr = config.mgr;
35487     var pos = config.region;
35488     config.skipConfig = true;
35489     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35490     
35491     if (mgr.el) {
35492         this.onRender(mgr.el);   
35493     }
35494      
35495     this.visible = true;
35496     this.collapsed = false;
35497     this.unrendered_panels = [];
35498 };
35499
35500 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35501
35502     position: '', // set by wrapper (eg. north/south etc..)
35503     unrendered_panels : null,  // unrendered panels.
35504     createBody : function(){
35505         /** This region's body element 
35506         * @type Roo.Element */
35507         this.bodyEl = this.el.createChild({
35508                 tag: "div",
35509                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35510         });
35511     },
35512
35513     onRender: function(ctr, pos)
35514     {
35515         var dh = Roo.DomHelper;
35516         /** This region's container element 
35517         * @type Roo.Element */
35518         this.el = dh.append(ctr.dom, {
35519                 tag: "div",
35520                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35521             }, true);
35522         /** This region's title element 
35523         * @type Roo.Element */
35524     
35525         this.titleEl = dh.append(this.el.dom,
35526             {
35527                     tag: "div",
35528                     unselectable: "on",
35529                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35530                     children:[
35531                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35532                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35533                     ]}, true);
35534         
35535         this.titleEl.enableDisplayMode();
35536         /** This region's title text element 
35537         * @type HTMLElement */
35538         this.titleTextEl = this.titleEl.dom.firstChild;
35539         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35540         /*
35541         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35542         this.closeBtn.enableDisplayMode();
35543         this.closeBtn.on("click", this.closeClicked, this);
35544         this.closeBtn.hide();
35545     */
35546         this.createBody(this.config);
35547         if(this.config.hideWhenEmpty){
35548             this.hide();
35549             this.on("paneladded", this.validateVisibility, this);
35550             this.on("panelremoved", this.validateVisibility, this);
35551         }
35552         if(this.autoScroll){
35553             this.bodyEl.setStyle("overflow", "auto");
35554         }else{
35555             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35556         }
35557         //if(c.titlebar !== false){
35558             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35559                 this.titleEl.hide();
35560             }else{
35561                 this.titleEl.show();
35562                 if(this.config.title){
35563                     this.titleTextEl.innerHTML = this.config.title;
35564                 }
35565             }
35566         //}
35567         if(this.config.collapsed){
35568             this.collapse(true);
35569         }
35570         if(this.config.hidden){
35571             this.hide();
35572         }
35573         
35574         if (this.unrendered_panels && this.unrendered_panels.length) {
35575             for (var i =0;i< this.unrendered_panels.length; i++) {
35576                 this.add(this.unrendered_panels[i]);
35577             }
35578             this.unrendered_panels = null;
35579             
35580         }
35581         
35582     },
35583     
35584     applyConfig : function(c)
35585     {
35586         /*
35587          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35588             var dh = Roo.DomHelper;
35589             if(c.titlebar !== false){
35590                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35591                 this.collapseBtn.on("click", this.collapse, this);
35592                 this.collapseBtn.enableDisplayMode();
35593                 /*
35594                 if(c.showPin === true || this.showPin){
35595                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35596                     this.stickBtn.enableDisplayMode();
35597                     this.stickBtn.on("click", this.expand, this);
35598                     this.stickBtn.hide();
35599                 }
35600                 
35601             }
35602             */
35603             /** This region's collapsed element
35604             * @type Roo.Element */
35605             /*
35606              *
35607             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35608                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35609             ]}, true);
35610             
35611             if(c.floatable !== false){
35612                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35613                this.collapsedEl.on("click", this.collapseClick, this);
35614             }
35615
35616             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35617                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35618                    id: "message", unselectable: "on", style:{"float":"left"}});
35619                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35620              }
35621             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35622             this.expandBtn.on("click", this.expand, this);
35623             
35624         }
35625         
35626         if(this.collapseBtn){
35627             this.collapseBtn.setVisible(c.collapsible == true);
35628         }
35629         
35630         this.cmargins = c.cmargins || this.cmargins ||
35631                          (this.position == "west" || this.position == "east" ?
35632                              {top: 0, left: 2, right:2, bottom: 0} :
35633                              {top: 2, left: 0, right:0, bottom: 2});
35634         */
35635         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35636         
35637         
35638         this.bottomTabs = c.tabPosition != "top";
35639         
35640         this.autoScroll = c.autoScroll || false;
35641         
35642         
35643        
35644         
35645         this.duration = c.duration || .30;
35646         this.slideDuration = c.slideDuration || .45;
35647         this.config = c;
35648        
35649     },
35650     /**
35651      * Returns true if this region is currently visible.
35652      * @return {Boolean}
35653      */
35654     isVisible : function(){
35655         return this.visible;
35656     },
35657
35658     /**
35659      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35660      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35661      */
35662     //setCollapsedTitle : function(title){
35663     //    title = title || "&#160;";
35664      //   if(this.collapsedTitleTextEl){
35665       //      this.collapsedTitleTextEl.innerHTML = title;
35666        // }
35667     //},
35668
35669     getBox : function(){
35670         var b;
35671       //  if(!this.collapsed){
35672             b = this.el.getBox(false, true);
35673        // }else{
35674           //  b = this.collapsedEl.getBox(false, true);
35675         //}
35676         return b;
35677     },
35678
35679     getMargins : function(){
35680         return this.margins;
35681         //return this.collapsed ? this.cmargins : this.margins;
35682     },
35683 /*
35684     highlight : function(){
35685         this.el.addClass("x-layout-panel-dragover");
35686     },
35687
35688     unhighlight : function(){
35689         this.el.removeClass("x-layout-panel-dragover");
35690     },
35691 */
35692     updateBox : function(box)
35693     {
35694         if (!this.bodyEl) {
35695             return; // not rendered yet..
35696         }
35697         
35698         this.box = box;
35699         if(!this.collapsed){
35700             this.el.dom.style.left = box.x + "px";
35701             this.el.dom.style.top = box.y + "px";
35702             this.updateBody(box.width, box.height);
35703         }else{
35704             this.collapsedEl.dom.style.left = box.x + "px";
35705             this.collapsedEl.dom.style.top = box.y + "px";
35706             this.collapsedEl.setSize(box.width, box.height);
35707         }
35708         if(this.tabs){
35709             this.tabs.autoSizeTabs();
35710         }
35711     },
35712
35713     updateBody : function(w, h)
35714     {
35715         if(w !== null){
35716             this.el.setWidth(w);
35717             w -= this.el.getBorderWidth("rl");
35718             if(this.config.adjustments){
35719                 w += this.config.adjustments[0];
35720             }
35721         }
35722         if(h !== null && h > 0){
35723             this.el.setHeight(h);
35724             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35725             h -= this.el.getBorderWidth("tb");
35726             if(this.config.adjustments){
35727                 h += this.config.adjustments[1];
35728             }
35729             this.bodyEl.setHeight(h);
35730             if(this.tabs){
35731                 h = this.tabs.syncHeight(h);
35732             }
35733         }
35734         if(this.panelSize){
35735             w = w !== null ? w : this.panelSize.width;
35736             h = h !== null ? h : this.panelSize.height;
35737         }
35738         if(this.activePanel){
35739             var el = this.activePanel.getEl();
35740             w = w !== null ? w : el.getWidth();
35741             h = h !== null ? h : el.getHeight();
35742             this.panelSize = {width: w, height: h};
35743             this.activePanel.setSize(w, h);
35744         }
35745         if(Roo.isIE && this.tabs){
35746             this.tabs.el.repaint();
35747         }
35748     },
35749
35750     /**
35751      * Returns the container element for this region.
35752      * @return {Roo.Element}
35753      */
35754     getEl : function(){
35755         return this.el;
35756     },
35757
35758     /**
35759      * Hides this region.
35760      */
35761     hide : function(){
35762         //if(!this.collapsed){
35763             this.el.dom.style.left = "-2000px";
35764             this.el.hide();
35765         //}else{
35766          //   this.collapsedEl.dom.style.left = "-2000px";
35767          //   this.collapsedEl.hide();
35768        // }
35769         this.visible = false;
35770         this.fireEvent("visibilitychange", this, false);
35771     },
35772
35773     /**
35774      * Shows this region if it was previously hidden.
35775      */
35776     show : function(){
35777         //if(!this.collapsed){
35778             this.el.show();
35779         //}else{
35780         //    this.collapsedEl.show();
35781        // }
35782         this.visible = true;
35783         this.fireEvent("visibilitychange", this, true);
35784     },
35785 /*
35786     closeClicked : function(){
35787         if(this.activePanel){
35788             this.remove(this.activePanel);
35789         }
35790     },
35791
35792     collapseClick : function(e){
35793         if(this.isSlid){
35794            e.stopPropagation();
35795            this.slideIn();
35796         }else{
35797            e.stopPropagation();
35798            this.slideOut();
35799         }
35800     },
35801 */
35802     /**
35803      * Collapses this region.
35804      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35805      */
35806     /*
35807     collapse : function(skipAnim, skipCheck = false){
35808         if(this.collapsed) {
35809             return;
35810         }
35811         
35812         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35813             
35814             this.collapsed = true;
35815             if(this.split){
35816                 this.split.el.hide();
35817             }
35818             if(this.config.animate && skipAnim !== true){
35819                 this.fireEvent("invalidated", this);
35820                 this.animateCollapse();
35821             }else{
35822                 this.el.setLocation(-20000,-20000);
35823                 this.el.hide();
35824                 this.collapsedEl.show();
35825                 this.fireEvent("collapsed", this);
35826                 this.fireEvent("invalidated", this);
35827             }
35828         }
35829         
35830     },
35831 */
35832     animateCollapse : function(){
35833         // overridden
35834     },
35835
35836     /**
35837      * Expands this region if it was previously collapsed.
35838      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35839      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35840      */
35841     /*
35842     expand : function(e, skipAnim){
35843         if(e) {
35844             e.stopPropagation();
35845         }
35846         if(!this.collapsed || this.el.hasActiveFx()) {
35847             return;
35848         }
35849         if(this.isSlid){
35850             this.afterSlideIn();
35851             skipAnim = true;
35852         }
35853         this.collapsed = false;
35854         if(this.config.animate && skipAnim !== true){
35855             this.animateExpand();
35856         }else{
35857             this.el.show();
35858             if(this.split){
35859                 this.split.el.show();
35860             }
35861             this.collapsedEl.setLocation(-2000,-2000);
35862             this.collapsedEl.hide();
35863             this.fireEvent("invalidated", this);
35864             this.fireEvent("expanded", this);
35865         }
35866     },
35867 */
35868     animateExpand : function(){
35869         // overridden
35870     },
35871
35872     initTabs : function()
35873     {
35874         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35875         
35876         var ts = new Roo.bootstrap.panel.Tabs({
35877                 el: this.bodyEl.dom,
35878                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35879                 disableTooltips: this.config.disableTabTips,
35880                 toolbar : this.config.toolbar
35881             });
35882         
35883         if(this.config.hideTabs){
35884             ts.stripWrap.setDisplayed(false);
35885         }
35886         this.tabs = ts;
35887         ts.resizeTabs = this.config.resizeTabs === true;
35888         ts.minTabWidth = this.config.minTabWidth || 40;
35889         ts.maxTabWidth = this.config.maxTabWidth || 250;
35890         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35891         ts.monitorResize = false;
35892         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35893         ts.bodyEl.addClass('roo-layout-tabs-body');
35894         this.panels.each(this.initPanelAsTab, this);
35895     },
35896
35897     initPanelAsTab : function(panel){
35898         var ti = this.tabs.addTab(
35899             panel.getEl().id,
35900             panel.getTitle(),
35901             null,
35902             this.config.closeOnTab && panel.isClosable(),
35903             panel.tpl
35904         );
35905         if(panel.tabTip !== undefined){
35906             ti.setTooltip(panel.tabTip);
35907         }
35908         ti.on("activate", function(){
35909               this.setActivePanel(panel);
35910         }, this);
35911         
35912         if(this.config.closeOnTab){
35913             ti.on("beforeclose", function(t, e){
35914                 e.cancel = true;
35915                 this.remove(panel);
35916             }, this);
35917         }
35918         
35919         panel.tabItem = ti;
35920         
35921         return ti;
35922     },
35923
35924     updatePanelTitle : function(panel, title)
35925     {
35926         if(this.activePanel == panel){
35927             this.updateTitle(title);
35928         }
35929         if(this.tabs){
35930             var ti = this.tabs.getTab(panel.getEl().id);
35931             ti.setText(title);
35932             if(panel.tabTip !== undefined){
35933                 ti.setTooltip(panel.tabTip);
35934             }
35935         }
35936     },
35937
35938     updateTitle : function(title){
35939         if(this.titleTextEl && !this.config.title){
35940             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35941         }
35942     },
35943
35944     setActivePanel : function(panel)
35945     {
35946         panel = this.getPanel(panel);
35947         if(this.activePanel && this.activePanel != panel){
35948             if(this.activePanel.setActiveState(false) === false){
35949                 return;
35950             }
35951         }
35952         this.activePanel = panel;
35953         panel.setActiveState(true);
35954         if(this.panelSize){
35955             panel.setSize(this.panelSize.width, this.panelSize.height);
35956         }
35957         if(this.closeBtn){
35958             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35959         }
35960         this.updateTitle(panel.getTitle());
35961         if(this.tabs){
35962             this.fireEvent("invalidated", this);
35963         }
35964         this.fireEvent("panelactivated", this, panel);
35965     },
35966
35967     /**
35968      * Shows the specified panel.
35969      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35970      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35971      */
35972     showPanel : function(panel)
35973     {
35974         panel = this.getPanel(panel);
35975         if(panel){
35976             if(this.tabs){
35977                 var tab = this.tabs.getTab(panel.getEl().id);
35978                 if(tab.isHidden()){
35979                     this.tabs.unhideTab(tab.id);
35980                 }
35981                 tab.activate();
35982             }else{
35983                 this.setActivePanel(panel);
35984             }
35985         }
35986         return panel;
35987     },
35988
35989     /**
35990      * Get the active panel for this region.
35991      * @return {Roo.ContentPanel} The active panel or null
35992      */
35993     getActivePanel : function(){
35994         return this.activePanel;
35995     },
35996
35997     validateVisibility : function(){
35998         if(this.panels.getCount() < 1){
35999             this.updateTitle("&#160;");
36000             this.closeBtn.hide();
36001             this.hide();
36002         }else{
36003             if(!this.isVisible()){
36004                 this.show();
36005             }
36006         }
36007     },
36008
36009     /**
36010      * Adds the passed ContentPanel(s) to this region.
36011      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36012      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36013      */
36014     add : function(panel)
36015     {
36016         if(arguments.length > 1){
36017             for(var i = 0, len = arguments.length; i < len; i++) {
36018                 this.add(arguments[i]);
36019             }
36020             return null;
36021         }
36022         
36023         // if we have not been rendered yet, then we can not really do much of this..
36024         if (!this.bodyEl) {
36025             this.unrendered_panels.push(panel);
36026             return panel;
36027         }
36028         
36029         
36030         
36031         
36032         if(this.hasPanel(panel)){
36033             this.showPanel(panel);
36034             return panel;
36035         }
36036         panel.setRegion(this);
36037         this.panels.add(panel);
36038        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36039             // sinle panel - no tab...?? would it not be better to render it with the tabs,
36040             // and hide them... ???
36041             this.bodyEl.dom.appendChild(panel.getEl().dom);
36042             if(panel.background !== true){
36043                 this.setActivePanel(panel);
36044             }
36045             this.fireEvent("paneladded", this, panel);
36046             return panel;
36047         }
36048         */
36049         if(!this.tabs){
36050             this.initTabs();
36051         }else{
36052             this.initPanelAsTab(panel);
36053         }
36054         
36055         
36056         if(panel.background !== true){
36057             this.tabs.activate(panel.getEl().id);
36058         }
36059         this.fireEvent("paneladded", this, panel);
36060         return panel;
36061     },
36062
36063     /**
36064      * Hides the tab for the specified panel.
36065      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36066      */
36067     hidePanel : function(panel){
36068         if(this.tabs && (panel = this.getPanel(panel))){
36069             this.tabs.hideTab(panel.getEl().id);
36070         }
36071     },
36072
36073     /**
36074      * Unhides the tab for a previously hidden panel.
36075      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36076      */
36077     unhidePanel : function(panel){
36078         if(this.tabs && (panel = this.getPanel(panel))){
36079             this.tabs.unhideTab(panel.getEl().id);
36080         }
36081     },
36082
36083     clearPanels : function(){
36084         while(this.panels.getCount() > 0){
36085              this.remove(this.panels.first());
36086         }
36087     },
36088
36089     /**
36090      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36091      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36092      * @param {Boolean} preservePanel Overrides the config preservePanel option
36093      * @return {Roo.ContentPanel} The panel that was removed
36094      */
36095     remove : function(panel, preservePanel)
36096     {
36097         panel = this.getPanel(panel);
36098         if(!panel){
36099             return null;
36100         }
36101         var e = {};
36102         this.fireEvent("beforeremove", this, panel, e);
36103         if(e.cancel === true){
36104             return null;
36105         }
36106         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36107         var panelId = panel.getId();
36108         this.panels.removeKey(panelId);
36109         if(preservePanel){
36110             document.body.appendChild(panel.getEl().dom);
36111         }
36112         if(this.tabs){
36113             this.tabs.removeTab(panel.getEl().id);
36114         }else if (!preservePanel){
36115             this.bodyEl.dom.removeChild(panel.getEl().dom);
36116         }
36117         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36118             var p = this.panels.first();
36119             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36120             tempEl.appendChild(p.getEl().dom);
36121             this.bodyEl.update("");
36122             this.bodyEl.dom.appendChild(p.getEl().dom);
36123             tempEl = null;
36124             this.updateTitle(p.getTitle());
36125             this.tabs = null;
36126             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36127             this.setActivePanel(p);
36128         }
36129         panel.setRegion(null);
36130         if(this.activePanel == panel){
36131             this.activePanel = null;
36132         }
36133         if(this.config.autoDestroy !== false && preservePanel !== true){
36134             try{panel.destroy();}catch(e){}
36135         }
36136         this.fireEvent("panelremoved", this, panel);
36137         return panel;
36138     },
36139
36140     /**
36141      * Returns the TabPanel component used by this region
36142      * @return {Roo.TabPanel}
36143      */
36144     getTabs : function(){
36145         return this.tabs;
36146     },
36147
36148     createTool : function(parentEl, className){
36149         var btn = Roo.DomHelper.append(parentEl, {
36150             tag: "div",
36151             cls: "x-layout-tools-button",
36152             children: [ {
36153                 tag: "div",
36154                 cls: "roo-layout-tools-button-inner " + className,
36155                 html: "&#160;"
36156             }]
36157         }, true);
36158         btn.addClassOnOver("roo-layout-tools-button-over");
36159         return btn;
36160     }
36161 });/*
36162  * Based on:
36163  * Ext JS Library 1.1.1
36164  * Copyright(c) 2006-2007, Ext JS, LLC.
36165  *
36166  * Originally Released Under LGPL - original licence link has changed is not relivant.
36167  *
36168  * Fork - LGPL
36169  * <script type="text/javascript">
36170  */
36171  
36172
36173
36174 /**
36175  * @class Roo.SplitLayoutRegion
36176  * @extends Roo.LayoutRegion
36177  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36178  */
36179 Roo.bootstrap.layout.Split = function(config){
36180     this.cursor = config.cursor;
36181     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36182 };
36183
36184 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36185 {
36186     splitTip : "Drag to resize.",
36187     collapsibleSplitTip : "Drag to resize. Double click to hide.",
36188     useSplitTips : false,
36189
36190     applyConfig : function(config){
36191         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36192     },
36193     
36194     onRender : function(ctr,pos) {
36195         
36196         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36197         if(!this.config.split){
36198             return;
36199         }
36200         if(!this.split){
36201             
36202             var splitEl = Roo.DomHelper.append(ctr.dom,  {
36203                             tag: "div",
36204                             id: this.el.id + "-split",
36205                             cls: "roo-layout-split roo-layout-split-"+this.position,
36206                             html: "&#160;"
36207             });
36208             /** The SplitBar for this region 
36209             * @type Roo.SplitBar */
36210             // does not exist yet...
36211             Roo.log([this.position, this.orientation]);
36212             
36213             this.split = new Roo.bootstrap.SplitBar({
36214                 dragElement : splitEl,
36215                 resizingElement: this.el,
36216                 orientation : this.orientation
36217             });
36218             
36219             this.split.on("moved", this.onSplitMove, this);
36220             this.split.useShim = this.config.useShim === true;
36221             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36222             if(this.useSplitTips){
36223                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36224             }
36225             //if(config.collapsible){
36226             //    this.split.el.on("dblclick", this.collapse,  this);
36227             //}
36228         }
36229         if(typeof this.config.minSize != "undefined"){
36230             this.split.minSize = this.config.minSize;
36231         }
36232         if(typeof this.config.maxSize != "undefined"){
36233             this.split.maxSize = this.config.maxSize;
36234         }
36235         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36236             this.hideSplitter();
36237         }
36238         
36239     },
36240
36241     getHMaxSize : function(){
36242          var cmax = this.config.maxSize || 10000;
36243          var center = this.mgr.getRegion("center");
36244          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36245     },
36246
36247     getVMaxSize : function(){
36248          var cmax = this.config.maxSize || 10000;
36249          var center = this.mgr.getRegion("center");
36250          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36251     },
36252
36253     onSplitMove : function(split, newSize){
36254         this.fireEvent("resized", this, newSize);
36255     },
36256     
36257     /** 
36258      * Returns the {@link Roo.SplitBar} for this region.
36259      * @return {Roo.SplitBar}
36260      */
36261     getSplitBar : function(){
36262         return this.split;
36263     },
36264     
36265     hide : function(){
36266         this.hideSplitter();
36267         Roo.bootstrap.layout.Split.superclass.hide.call(this);
36268     },
36269
36270     hideSplitter : function(){
36271         if(this.split){
36272             this.split.el.setLocation(-2000,-2000);
36273             this.split.el.hide();
36274         }
36275     },
36276
36277     show : function(){
36278         if(this.split){
36279             this.split.el.show();
36280         }
36281         Roo.bootstrap.layout.Split.superclass.show.call(this);
36282     },
36283     
36284     beforeSlide: function(){
36285         if(Roo.isGecko){// firefox overflow auto bug workaround
36286             this.bodyEl.clip();
36287             if(this.tabs) {
36288                 this.tabs.bodyEl.clip();
36289             }
36290             if(this.activePanel){
36291                 this.activePanel.getEl().clip();
36292                 
36293                 if(this.activePanel.beforeSlide){
36294                     this.activePanel.beforeSlide();
36295                 }
36296             }
36297         }
36298     },
36299     
36300     afterSlide : function(){
36301         if(Roo.isGecko){// firefox overflow auto bug workaround
36302             this.bodyEl.unclip();
36303             if(this.tabs) {
36304                 this.tabs.bodyEl.unclip();
36305             }
36306             if(this.activePanel){
36307                 this.activePanel.getEl().unclip();
36308                 if(this.activePanel.afterSlide){
36309                     this.activePanel.afterSlide();
36310                 }
36311             }
36312         }
36313     },
36314
36315     initAutoHide : function(){
36316         if(this.autoHide !== false){
36317             if(!this.autoHideHd){
36318                 var st = new Roo.util.DelayedTask(this.slideIn, this);
36319                 this.autoHideHd = {
36320                     "mouseout": function(e){
36321                         if(!e.within(this.el, true)){
36322                             st.delay(500);
36323                         }
36324                     },
36325                     "mouseover" : function(e){
36326                         st.cancel();
36327                     },
36328                     scope : this
36329                 };
36330             }
36331             this.el.on(this.autoHideHd);
36332         }
36333     },
36334
36335     clearAutoHide : function(){
36336         if(this.autoHide !== false){
36337             this.el.un("mouseout", this.autoHideHd.mouseout);
36338             this.el.un("mouseover", this.autoHideHd.mouseover);
36339         }
36340     },
36341
36342     clearMonitor : function(){
36343         Roo.get(document).un("click", this.slideInIf, this);
36344     },
36345
36346     // these names are backwards but not changed for compat
36347     slideOut : function(){
36348         if(this.isSlid || this.el.hasActiveFx()){
36349             return;
36350         }
36351         this.isSlid = true;
36352         if(this.collapseBtn){
36353             this.collapseBtn.hide();
36354         }
36355         this.closeBtnState = this.closeBtn.getStyle('display');
36356         this.closeBtn.hide();
36357         if(this.stickBtn){
36358             this.stickBtn.show();
36359         }
36360         this.el.show();
36361         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36362         this.beforeSlide();
36363         this.el.setStyle("z-index", 10001);
36364         this.el.slideIn(this.getSlideAnchor(), {
36365             callback: function(){
36366                 this.afterSlide();
36367                 this.initAutoHide();
36368                 Roo.get(document).on("click", this.slideInIf, this);
36369                 this.fireEvent("slideshow", this);
36370             },
36371             scope: this,
36372             block: true
36373         });
36374     },
36375
36376     afterSlideIn : function(){
36377         this.clearAutoHide();
36378         this.isSlid = false;
36379         this.clearMonitor();
36380         this.el.setStyle("z-index", "");
36381         if(this.collapseBtn){
36382             this.collapseBtn.show();
36383         }
36384         this.closeBtn.setStyle('display', this.closeBtnState);
36385         if(this.stickBtn){
36386             this.stickBtn.hide();
36387         }
36388         this.fireEvent("slidehide", this);
36389     },
36390
36391     slideIn : function(cb){
36392         if(!this.isSlid || this.el.hasActiveFx()){
36393             Roo.callback(cb);
36394             return;
36395         }
36396         this.isSlid = false;
36397         this.beforeSlide();
36398         this.el.slideOut(this.getSlideAnchor(), {
36399             callback: function(){
36400                 this.el.setLeftTop(-10000, -10000);
36401                 this.afterSlide();
36402                 this.afterSlideIn();
36403                 Roo.callback(cb);
36404             },
36405             scope: this,
36406             block: true
36407         });
36408     },
36409     
36410     slideInIf : function(e){
36411         if(!e.within(this.el)){
36412             this.slideIn();
36413         }
36414     },
36415
36416     animateCollapse : function(){
36417         this.beforeSlide();
36418         this.el.setStyle("z-index", 20000);
36419         var anchor = this.getSlideAnchor();
36420         this.el.slideOut(anchor, {
36421             callback : function(){
36422                 this.el.setStyle("z-index", "");
36423                 this.collapsedEl.slideIn(anchor, {duration:.3});
36424                 this.afterSlide();
36425                 this.el.setLocation(-10000,-10000);
36426                 this.el.hide();
36427                 this.fireEvent("collapsed", this);
36428             },
36429             scope: this,
36430             block: true
36431         });
36432     },
36433
36434     animateExpand : function(){
36435         this.beforeSlide();
36436         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36437         this.el.setStyle("z-index", 20000);
36438         this.collapsedEl.hide({
36439             duration:.1
36440         });
36441         this.el.slideIn(this.getSlideAnchor(), {
36442             callback : function(){
36443                 this.el.setStyle("z-index", "");
36444                 this.afterSlide();
36445                 if(this.split){
36446                     this.split.el.show();
36447                 }
36448                 this.fireEvent("invalidated", this);
36449                 this.fireEvent("expanded", this);
36450             },
36451             scope: this,
36452             block: true
36453         });
36454     },
36455
36456     anchors : {
36457         "west" : "left",
36458         "east" : "right",
36459         "north" : "top",
36460         "south" : "bottom"
36461     },
36462
36463     sanchors : {
36464         "west" : "l",
36465         "east" : "r",
36466         "north" : "t",
36467         "south" : "b"
36468     },
36469
36470     canchors : {
36471         "west" : "tl-tr",
36472         "east" : "tr-tl",
36473         "north" : "tl-bl",
36474         "south" : "bl-tl"
36475     },
36476
36477     getAnchor : function(){
36478         return this.anchors[this.position];
36479     },
36480
36481     getCollapseAnchor : function(){
36482         return this.canchors[this.position];
36483     },
36484
36485     getSlideAnchor : function(){
36486         return this.sanchors[this.position];
36487     },
36488
36489     getAlignAdj : function(){
36490         var cm = this.cmargins;
36491         switch(this.position){
36492             case "west":
36493                 return [0, 0];
36494             break;
36495             case "east":
36496                 return [0, 0];
36497             break;
36498             case "north":
36499                 return [0, 0];
36500             break;
36501             case "south":
36502                 return [0, 0];
36503             break;
36504         }
36505     },
36506
36507     getExpandAdj : function(){
36508         var c = this.collapsedEl, cm = this.cmargins;
36509         switch(this.position){
36510             case "west":
36511                 return [-(cm.right+c.getWidth()+cm.left), 0];
36512             break;
36513             case "east":
36514                 return [cm.right+c.getWidth()+cm.left, 0];
36515             break;
36516             case "north":
36517                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36518             break;
36519             case "south":
36520                 return [0, cm.top+cm.bottom+c.getHeight()];
36521             break;
36522         }
36523     }
36524 });/*
36525  * Based on:
36526  * Ext JS Library 1.1.1
36527  * Copyright(c) 2006-2007, Ext JS, LLC.
36528  *
36529  * Originally Released Under LGPL - original licence link has changed is not relivant.
36530  *
36531  * Fork - LGPL
36532  * <script type="text/javascript">
36533  */
36534 /*
36535  * These classes are private internal classes
36536  */
36537 Roo.bootstrap.layout.Center = function(config){
36538     config.region = "center";
36539     Roo.bootstrap.layout.Region.call(this, config);
36540     this.visible = true;
36541     this.minWidth = config.minWidth || 20;
36542     this.minHeight = config.minHeight || 20;
36543 };
36544
36545 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36546     hide : function(){
36547         // center panel can't be hidden
36548     },
36549     
36550     show : function(){
36551         // center panel can't be hidden
36552     },
36553     
36554     getMinWidth: function(){
36555         return this.minWidth;
36556     },
36557     
36558     getMinHeight: function(){
36559         return this.minHeight;
36560     }
36561 });
36562
36563
36564
36565
36566  
36567
36568
36569
36570
36571
36572 Roo.bootstrap.layout.North = function(config)
36573 {
36574     config.region = 'north';
36575     config.cursor = 'n-resize';
36576     
36577     Roo.bootstrap.layout.Split.call(this, config);
36578     
36579     
36580     if(this.split){
36581         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36582         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36583         this.split.el.addClass("roo-layout-split-v");
36584     }
36585     var size = config.initialSize || config.height;
36586     if(typeof size != "undefined"){
36587         this.el.setHeight(size);
36588     }
36589 };
36590 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36591 {
36592     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36593     
36594     
36595     
36596     getBox : function(){
36597         if(this.collapsed){
36598             return this.collapsedEl.getBox();
36599         }
36600         var box = this.el.getBox();
36601         if(this.split){
36602             box.height += this.split.el.getHeight();
36603         }
36604         return box;
36605     },
36606     
36607     updateBox : function(box){
36608         if(this.split && !this.collapsed){
36609             box.height -= this.split.el.getHeight();
36610             this.split.el.setLeft(box.x);
36611             this.split.el.setTop(box.y+box.height);
36612             this.split.el.setWidth(box.width);
36613         }
36614         if(this.collapsed){
36615             this.updateBody(box.width, null);
36616         }
36617         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36618     }
36619 });
36620
36621
36622
36623
36624
36625 Roo.bootstrap.layout.South = function(config){
36626     config.region = 'south';
36627     config.cursor = 's-resize';
36628     Roo.bootstrap.layout.Split.call(this, config);
36629     if(this.split){
36630         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36631         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36632         this.split.el.addClass("roo-layout-split-v");
36633     }
36634     var size = config.initialSize || config.height;
36635     if(typeof size != "undefined"){
36636         this.el.setHeight(size);
36637     }
36638 };
36639
36640 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36641     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36642     getBox : function(){
36643         if(this.collapsed){
36644             return this.collapsedEl.getBox();
36645         }
36646         var box = this.el.getBox();
36647         if(this.split){
36648             var sh = this.split.el.getHeight();
36649             box.height += sh;
36650             box.y -= sh;
36651         }
36652         return box;
36653     },
36654     
36655     updateBox : function(box){
36656         if(this.split && !this.collapsed){
36657             var sh = this.split.el.getHeight();
36658             box.height -= sh;
36659             box.y += sh;
36660             this.split.el.setLeft(box.x);
36661             this.split.el.setTop(box.y-sh);
36662             this.split.el.setWidth(box.width);
36663         }
36664         if(this.collapsed){
36665             this.updateBody(box.width, null);
36666         }
36667         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36668     }
36669 });
36670
36671 Roo.bootstrap.layout.East = function(config){
36672     config.region = "east";
36673     config.cursor = "e-resize";
36674     Roo.bootstrap.layout.Split.call(this, config);
36675     if(this.split){
36676         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36677         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36678         this.split.el.addClass("roo-layout-split-h");
36679     }
36680     var size = config.initialSize || config.width;
36681     if(typeof size != "undefined"){
36682         this.el.setWidth(size);
36683     }
36684 };
36685 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36686     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36687     getBox : function(){
36688         if(this.collapsed){
36689             return this.collapsedEl.getBox();
36690         }
36691         var box = this.el.getBox();
36692         if(this.split){
36693             var sw = this.split.el.getWidth();
36694             box.width += sw;
36695             box.x -= sw;
36696         }
36697         return box;
36698     },
36699
36700     updateBox : function(box){
36701         if(this.split && !this.collapsed){
36702             var sw = this.split.el.getWidth();
36703             box.width -= sw;
36704             this.split.el.setLeft(box.x);
36705             this.split.el.setTop(box.y);
36706             this.split.el.setHeight(box.height);
36707             box.x += sw;
36708         }
36709         if(this.collapsed){
36710             this.updateBody(null, box.height);
36711         }
36712         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36713     }
36714 });
36715
36716 Roo.bootstrap.layout.West = function(config){
36717     config.region = "west";
36718     config.cursor = "w-resize";
36719     
36720     Roo.bootstrap.layout.Split.call(this, config);
36721     if(this.split){
36722         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36723         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36724         this.split.el.addClass("roo-layout-split-h");
36725     }
36726     
36727 };
36728 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36729     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36730     
36731     onRender: function(ctr, pos)
36732     {
36733         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36734         var size = this.config.initialSize || this.config.width;
36735         if(typeof size != "undefined"){
36736             this.el.setWidth(size);
36737         }
36738     },
36739     
36740     getBox : function(){
36741         if(this.collapsed){
36742             return this.collapsedEl.getBox();
36743         }
36744         var box = this.el.getBox();
36745         if(this.split){
36746             box.width += this.split.el.getWidth();
36747         }
36748         return box;
36749     },
36750     
36751     updateBox : function(box){
36752         if(this.split && !this.collapsed){
36753             var sw = this.split.el.getWidth();
36754             box.width -= sw;
36755             this.split.el.setLeft(box.x+box.width);
36756             this.split.el.setTop(box.y);
36757             this.split.el.setHeight(box.height);
36758         }
36759         if(this.collapsed){
36760             this.updateBody(null, box.height);
36761         }
36762         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36763     }
36764 });
36765 Roo.namespace("Roo.bootstrap.panel");/*
36766  * Based on:
36767  * Ext JS Library 1.1.1
36768  * Copyright(c) 2006-2007, Ext JS, LLC.
36769  *
36770  * Originally Released Under LGPL - original licence link has changed is not relivant.
36771  *
36772  * Fork - LGPL
36773  * <script type="text/javascript">
36774  */
36775 /**
36776  * @class Roo.ContentPanel
36777  * @extends Roo.util.Observable
36778  * A basic ContentPanel element.
36779  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36780  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36781  * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
36782  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36783  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36784  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36785  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36786  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36787  * @cfg {String} title          The title for this panel
36788  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36789  * @cfg {String} url            Calls {@link #setUrl} with this value
36790  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36791  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36792  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36793  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36794  * @cfg {Boolean} badges render the badges
36795
36796  * @constructor
36797  * Create a new ContentPanel.
36798  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36799  * @param {String/Object} config A string to set only the title or a config object
36800  * @param {String} content (optional) Set the HTML content for this panel
36801  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36802  */
36803 Roo.bootstrap.panel.Content = function( config){
36804     
36805     this.tpl = config.tpl || false;
36806     
36807     var el = config.el;
36808     var content = config.content;
36809
36810     if(config.autoCreate){ // xtype is available if this is called from factory
36811         el = Roo.id();
36812     }
36813     this.el = Roo.get(el);
36814     if(!this.el && config && config.autoCreate){
36815         if(typeof config.autoCreate == "object"){
36816             if(!config.autoCreate.id){
36817                 config.autoCreate.id = config.id||el;
36818             }
36819             this.el = Roo.DomHelper.append(document.body,
36820                         config.autoCreate, true);
36821         }else{
36822             var elcfg =  {   tag: "div",
36823                             cls: "roo-layout-inactive-content",
36824                             id: config.id||el
36825                             };
36826             if (config.html) {
36827                 elcfg.html = config.html;
36828                 
36829             }
36830                         
36831             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36832         }
36833     } 
36834     this.closable = false;
36835     this.loaded = false;
36836     this.active = false;
36837    
36838       
36839     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36840         
36841         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36842         
36843         this.wrapEl = this.el; //this.el.wrap();
36844         var ti = [];
36845         if (config.toolbar.items) {
36846             ti = config.toolbar.items ;
36847             delete config.toolbar.items ;
36848         }
36849         
36850         var nitems = [];
36851         this.toolbar.render(this.wrapEl, 'before');
36852         for(var i =0;i < ti.length;i++) {
36853           //  Roo.log(['add child', items[i]]);
36854             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36855         }
36856         this.toolbar.items = nitems;
36857         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36858         delete config.toolbar;
36859         
36860     }
36861     /*
36862     // xtype created footer. - not sure if will work as we normally have to render first..
36863     if (this.footer && !this.footer.el && this.footer.xtype) {
36864         if (!this.wrapEl) {
36865             this.wrapEl = this.el.wrap();
36866         }
36867     
36868         this.footer.container = this.wrapEl.createChild();
36869          
36870         this.footer = Roo.factory(this.footer, Roo);
36871         
36872     }
36873     */
36874     
36875      if(typeof config == "string"){
36876         this.title = config;
36877     }else{
36878         Roo.apply(this, config);
36879     }
36880     
36881     if(this.resizeEl){
36882         this.resizeEl = Roo.get(this.resizeEl, true);
36883     }else{
36884         this.resizeEl = this.el;
36885     }
36886     // handle view.xtype
36887     
36888  
36889     
36890     
36891     this.addEvents({
36892         /**
36893          * @event activate
36894          * Fires when this panel is activated. 
36895          * @param {Roo.ContentPanel} this
36896          */
36897         "activate" : true,
36898         /**
36899          * @event deactivate
36900          * Fires when this panel is activated. 
36901          * @param {Roo.ContentPanel} this
36902          */
36903         "deactivate" : true,
36904
36905         /**
36906          * @event resize
36907          * Fires when this panel is resized if fitToFrame is true.
36908          * @param {Roo.ContentPanel} this
36909          * @param {Number} width The width after any component adjustments
36910          * @param {Number} height The height after any component adjustments
36911          */
36912         "resize" : true,
36913         
36914          /**
36915          * @event render
36916          * Fires when this tab is created
36917          * @param {Roo.ContentPanel} this
36918          */
36919         "render" : true
36920         
36921         
36922         
36923     });
36924     
36925
36926     
36927     
36928     if(this.autoScroll){
36929         this.resizeEl.setStyle("overflow", "auto");
36930     } else {
36931         // fix randome scrolling
36932         //this.el.on('scroll', function() {
36933         //    Roo.log('fix random scolling');
36934         //    this.scrollTo('top',0); 
36935         //});
36936     }
36937     content = content || this.content;
36938     if(content){
36939         this.setContent(content);
36940     }
36941     if(config && config.url){
36942         this.setUrl(this.url, this.params, this.loadOnce);
36943     }
36944     
36945     
36946     
36947     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36948     
36949     if (this.view && typeof(this.view.xtype) != 'undefined') {
36950         this.view.el = this.el.appendChild(document.createElement("div"));
36951         this.view = Roo.factory(this.view); 
36952         this.view.render  &&  this.view.render(false, '');  
36953     }
36954     
36955     
36956     this.fireEvent('render', this);
36957 };
36958
36959 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36960     
36961     tabTip : '',
36962     
36963     setRegion : function(region){
36964         this.region = region;
36965         this.setActiveClass(region && !this.background);
36966     },
36967     
36968     
36969     setActiveClass: function(state)
36970     {
36971         if(state){
36972            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36973            this.el.setStyle('position','relative');
36974         }else{
36975            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36976            this.el.setStyle('position', 'absolute');
36977         } 
36978     },
36979     
36980     /**
36981      * Returns the toolbar for this Panel if one was configured. 
36982      * @return {Roo.Toolbar} 
36983      */
36984     getToolbar : function(){
36985         return this.toolbar;
36986     },
36987     
36988     setActiveState : function(active)
36989     {
36990         this.active = active;
36991         this.setActiveClass(active);
36992         if(!active){
36993             if(this.fireEvent("deactivate", this) === false){
36994                 return false;
36995             }
36996             return true;
36997         }
36998         this.fireEvent("activate", this);
36999         return true;
37000     },
37001     /**
37002      * Updates this panel's element
37003      * @param {String} content The new content
37004      * @param {Boolean} loadScripts (optional) true to look for and process scripts
37005     */
37006     setContent : function(content, loadScripts){
37007         this.el.update(content, loadScripts);
37008     },
37009
37010     ignoreResize : function(w, h){
37011         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37012             return true;
37013         }else{
37014             this.lastSize = {width: w, height: h};
37015             return false;
37016         }
37017     },
37018     /**
37019      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37020      * @return {Roo.UpdateManager} The UpdateManager
37021      */
37022     getUpdateManager : function(){
37023         return this.el.getUpdateManager();
37024     },
37025      /**
37026      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37027      * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
37028 <pre><code>
37029 panel.load({
37030     url: "your-url.php",
37031     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37032     callback: yourFunction,
37033     scope: yourObject, //(optional scope)
37034     discardUrl: false,
37035     nocache: false,
37036     text: "Loading...",
37037     timeout: 30,
37038     scripts: false
37039 });
37040 </code></pre>
37041      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37042      * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
37043      * @param {String/Object} params (optional) The parameters to pass as either a URL encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
37044      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37045      * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
37046      * @return {Roo.ContentPanel} this
37047      */
37048     load : function(){
37049         var um = this.el.getUpdateManager();
37050         um.update.apply(um, arguments);
37051         return this;
37052     },
37053
37054
37055     /**
37056      * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
37057      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37058      * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
37059      * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
37060      * @return {Roo.UpdateManager} The UpdateManager
37061      */
37062     setUrl : function(url, params, loadOnce){
37063         if(this.refreshDelegate){
37064             this.removeListener("activate", this.refreshDelegate);
37065         }
37066         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37067         this.on("activate", this.refreshDelegate);
37068         return this.el.getUpdateManager();
37069     },
37070     
37071     _handleRefresh : function(url, params, loadOnce){
37072         if(!loadOnce || !this.loaded){
37073             var updater = this.el.getUpdateManager();
37074             updater.update(url, params, this._setLoaded.createDelegate(this));
37075         }
37076     },
37077     
37078     _setLoaded : function(){
37079         this.loaded = true;
37080     }, 
37081     
37082     /**
37083      * Returns this panel's id
37084      * @return {String} 
37085      */
37086     getId : function(){
37087         return this.el.id;
37088     },
37089     
37090     /** 
37091      * Returns this panel's element - used by regiosn to add.
37092      * @return {Roo.Element} 
37093      */
37094     getEl : function(){
37095         return this.wrapEl || this.el;
37096     },
37097     
37098    
37099     
37100     adjustForComponents : function(width, height)
37101     {
37102         //Roo.log('adjustForComponents ');
37103         if(this.resizeEl != this.el){
37104             width -= this.el.getFrameWidth('lr');
37105             height -= this.el.getFrameWidth('tb');
37106         }
37107         if(this.toolbar){
37108             var te = this.toolbar.getEl();
37109             te.setWidth(width);
37110             height -= te.getHeight();
37111         }
37112         if(this.footer){
37113             var te = this.footer.getEl();
37114             te.setWidth(width);
37115             height -= te.getHeight();
37116         }
37117         
37118         
37119         if(this.adjustments){
37120             width += this.adjustments[0];
37121             height += this.adjustments[1];
37122         }
37123         return {"width": width, "height": height};
37124     },
37125     
37126     setSize : function(width, height){
37127         if(this.fitToFrame && !this.ignoreResize(width, height)){
37128             if(this.fitContainer && this.resizeEl != this.el){
37129                 this.el.setSize(width, height);
37130             }
37131             var size = this.adjustForComponents(width, height);
37132             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37133             this.fireEvent('resize', this, size.width, size.height);
37134         }
37135     },
37136     
37137     /**
37138      * Returns this panel's title
37139      * @return {String} 
37140      */
37141     getTitle : function(){
37142         
37143         if (typeof(this.title) != 'object') {
37144             return this.title;
37145         }
37146         
37147         var t = '';
37148         for (var k in this.title) {
37149             if (!this.title.hasOwnProperty(k)) {
37150                 continue;
37151             }
37152             
37153             if (k.indexOf('-') >= 0) {
37154                 var s = k.split('-');
37155                 for (var i = 0; i<s.length; i++) {
37156                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37157                 }
37158             } else {
37159                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37160             }
37161         }
37162         return t;
37163     },
37164     
37165     /**
37166      * Set this panel's title
37167      * @param {String} title
37168      */
37169     setTitle : function(title){
37170         this.title = title;
37171         if(this.region){
37172             this.region.updatePanelTitle(this, title);
37173         }
37174     },
37175     
37176     /**
37177      * Returns true is this panel was configured to be closable
37178      * @return {Boolean} 
37179      */
37180     isClosable : function(){
37181         return this.closable;
37182     },
37183     
37184     beforeSlide : function(){
37185         this.el.clip();
37186         this.resizeEl.clip();
37187     },
37188     
37189     afterSlide : function(){
37190         this.el.unclip();
37191         this.resizeEl.unclip();
37192     },
37193     
37194     /**
37195      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
37196      *   Will fail silently if the {@link #setUrl} method has not been called.
37197      *   This does not activate the panel, just updates its content.
37198      */
37199     refresh : function(){
37200         if(this.refreshDelegate){
37201            this.loaded = false;
37202            this.refreshDelegate();
37203         }
37204     },
37205     
37206     /**
37207      * Destroys this panel
37208      */
37209     destroy : function(){
37210         this.el.removeAllListeners();
37211         var tempEl = document.createElement("span");
37212         tempEl.appendChild(this.el.dom);
37213         tempEl.innerHTML = "";
37214         this.el.remove();
37215         this.el = null;
37216     },
37217     
37218     /**
37219      * form - if the content panel contains a form - this is a reference to it.
37220      * @type {Roo.form.Form}
37221      */
37222     form : false,
37223     /**
37224      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37225      *    This contains a reference to it.
37226      * @type {Roo.View}
37227      */
37228     view : false,
37229     
37230       /**
37231      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37232      * <pre><code>
37233
37234 layout.addxtype({
37235        xtype : 'Form',
37236        items: [ .... ]
37237    }
37238 );
37239
37240 </code></pre>
37241      * @param {Object} cfg Xtype definition of item to add.
37242      */
37243     
37244     
37245     getChildContainer: function () {
37246         return this.getEl();
37247     }
37248     
37249     
37250     /*
37251         var  ret = new Roo.factory(cfg);
37252         return ret;
37253         
37254         
37255         // add form..
37256         if (cfg.xtype.match(/^Form$/)) {
37257             
37258             var el;
37259             //if (this.footer) {
37260             //    el = this.footer.container.insertSibling(false, 'before');
37261             //} else {
37262                 el = this.el.createChild();
37263             //}
37264
37265             this.form = new  Roo.form.Form(cfg);
37266             
37267             
37268             if ( this.form.allItems.length) {
37269                 this.form.render(el.dom);
37270             }
37271             return this.form;
37272         }
37273         // should only have one of theses..
37274         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37275             // views.. should not be just added - used named prop 'view''
37276             
37277             cfg.el = this.el.appendChild(document.createElement("div"));
37278             // factory?
37279             
37280             var ret = new Roo.factory(cfg);
37281              
37282              ret.render && ret.render(false, ''); // render blank..
37283             this.view = ret;
37284             return ret;
37285         }
37286         return false;
37287     }
37288     \*/
37289 });
37290  
37291 /**
37292  * @class Roo.bootstrap.panel.Grid
37293  * @extends Roo.bootstrap.panel.Content
37294  * @constructor
37295  * Create a new GridPanel.
37296  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37297  * @param {Object} config A the config object
37298   
37299  */
37300
37301
37302
37303 Roo.bootstrap.panel.Grid = function(config)
37304 {
37305     
37306       
37307     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37308         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37309
37310     config.el = this.wrapper;
37311     //this.el = this.wrapper;
37312     
37313       if (config.container) {
37314         // ctor'ed from a Border/panel.grid
37315         
37316         
37317         this.wrapper.setStyle("overflow", "hidden");
37318         this.wrapper.addClass('roo-grid-container');
37319
37320     }
37321     
37322     
37323     if(config.toolbar){
37324         var tool_el = this.wrapper.createChild();    
37325         this.toolbar = Roo.factory(config.toolbar);
37326         var ti = [];
37327         if (config.toolbar.items) {
37328             ti = config.toolbar.items ;
37329             delete config.toolbar.items ;
37330         }
37331         
37332         var nitems = [];
37333         this.toolbar.render(tool_el);
37334         for(var i =0;i < ti.length;i++) {
37335           //  Roo.log(['add child', items[i]]);
37336             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37337         }
37338         this.toolbar.items = nitems;
37339         
37340         delete config.toolbar;
37341     }
37342     
37343     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37344     config.grid.scrollBody = true;;
37345     config.grid.monitorWindowResize = false; // turn off autosizing
37346     config.grid.autoHeight = false;
37347     config.grid.autoWidth = false;
37348     
37349     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37350     
37351     if (config.background) {
37352         // render grid on panel activation (if panel background)
37353         this.on('activate', function(gp) {
37354             if (!gp.grid.rendered) {
37355                 gp.grid.render(this.wrapper);
37356                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37357             }
37358         });
37359             
37360     } else {
37361         this.grid.render(this.wrapper);
37362         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37363
37364     }
37365     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37366     // ??? needed ??? config.el = this.wrapper;
37367     
37368     
37369     
37370   
37371     // xtype created footer. - not sure if will work as we normally have to render first..
37372     if (this.footer && !this.footer.el && this.footer.xtype) {
37373         
37374         var ctr = this.grid.getView().getFooterPanel(true);
37375         this.footer.dataSource = this.grid.dataSource;
37376         this.footer = Roo.factory(this.footer, Roo);
37377         this.footer.render(ctr);
37378         
37379     }
37380     
37381     
37382     
37383     
37384      
37385 };
37386
37387 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37388     getId : function(){
37389         return this.grid.id;
37390     },
37391     
37392     /**
37393      * Returns the grid for this panel
37394      * @return {Roo.bootstrap.Table} 
37395      */
37396     getGrid : function(){
37397         return this.grid;    
37398     },
37399     
37400     setSize : function(width, height){
37401         if(!this.ignoreResize(width, height)){
37402             var grid = this.grid;
37403             var size = this.adjustForComponents(width, height);
37404             var gridel = grid.getGridEl();
37405             gridel.setSize(size.width, size.height);
37406             /*
37407             var thd = grid.getGridEl().select('thead',true).first();
37408             var tbd = grid.getGridEl().select('tbody', true).first();
37409             if (tbd) {
37410                 tbd.setSize(width, height - thd.getHeight());
37411             }
37412             */
37413             grid.autoSize();
37414         }
37415     },
37416      
37417     
37418     
37419     beforeSlide : function(){
37420         this.grid.getView().scroller.clip();
37421     },
37422     
37423     afterSlide : function(){
37424         this.grid.getView().scroller.unclip();
37425     },
37426     
37427     destroy : function(){
37428         this.grid.destroy();
37429         delete this.grid;
37430         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37431     }
37432 });
37433
37434 /**
37435  * @class Roo.bootstrap.panel.Nest
37436  * @extends Roo.bootstrap.panel.Content
37437  * @constructor
37438  * Create a new Panel, that can contain a layout.Border.
37439  * 
37440  * 
37441  * @param {Roo.BorderLayout} layout The layout for this panel
37442  * @param {String/Object} config A string to set only the title or a config object
37443  */
37444 Roo.bootstrap.panel.Nest = function(config)
37445 {
37446     // construct with only one argument..
37447     /* FIXME - implement nicer consturctors
37448     if (layout.layout) {
37449         config = layout;
37450         layout = config.layout;
37451         delete config.layout;
37452     }
37453     if (layout.xtype && !layout.getEl) {
37454         // then layout needs constructing..
37455         layout = Roo.factory(layout, Roo);
37456     }
37457     */
37458     
37459     config.el =  config.layout.getEl();
37460     
37461     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37462     
37463     config.layout.monitorWindowResize = false; // turn off autosizing
37464     this.layout = config.layout;
37465     this.layout.getEl().addClass("roo-layout-nested-layout");
37466     
37467     
37468     
37469     
37470 };
37471
37472 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37473
37474     setSize : function(width, height){
37475         if(!this.ignoreResize(width, height)){
37476             var size = this.adjustForComponents(width, height);
37477             var el = this.layout.getEl();
37478             if (size.height < 1) {
37479                 el.setWidth(size.width);   
37480             } else {
37481                 el.setSize(size.width, size.height);
37482             }
37483             var touch = el.dom.offsetWidth;
37484             this.layout.layout();
37485             // ie requires a double layout on the first pass
37486             if(Roo.isIE && !this.initialized){
37487                 this.initialized = true;
37488                 this.layout.layout();
37489             }
37490         }
37491     },
37492     
37493     // activate all subpanels if not currently active..
37494     
37495     setActiveState : function(active){
37496         this.active = active;
37497         this.setActiveClass(active);
37498         
37499         if(!active){
37500             this.fireEvent("deactivate", this);
37501             return;
37502         }
37503         
37504         this.fireEvent("activate", this);
37505         // not sure if this should happen before or after..
37506         if (!this.layout) {
37507             return; // should not happen..
37508         }
37509         var reg = false;
37510         for (var r in this.layout.regions) {
37511             reg = this.layout.getRegion(r);
37512             if (reg.getActivePanel()) {
37513                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37514                 reg.setActivePanel(reg.getActivePanel());
37515                 continue;
37516             }
37517             if (!reg.panels.length) {
37518                 continue;
37519             }
37520             reg.showPanel(reg.getPanel(0));
37521         }
37522         
37523         
37524         
37525         
37526     },
37527     
37528     /**
37529      * Returns the nested BorderLayout for this panel
37530      * @return {Roo.BorderLayout} 
37531      */
37532     getLayout : function(){
37533         return this.layout;
37534     },
37535     
37536      /**
37537      * Adds a xtype elements to the layout of the nested panel
37538      * <pre><code>
37539
37540 panel.addxtype({
37541        xtype : 'ContentPanel',
37542        region: 'west',
37543        items: [ .... ]
37544    }
37545 );
37546
37547 panel.addxtype({
37548         xtype : 'NestedLayoutPanel',
37549         region: 'west',
37550         layout: {
37551            center: { },
37552            west: { }   
37553         },
37554         items : [ ... list of content panels or nested layout panels.. ]
37555    }
37556 );
37557 </code></pre>
37558      * @param {Object} cfg Xtype definition of item to add.
37559      */
37560     addxtype : function(cfg) {
37561         return this.layout.addxtype(cfg);
37562     
37563     }
37564 });        /*
37565  * Based on:
37566  * Ext JS Library 1.1.1
37567  * Copyright(c) 2006-2007, Ext JS, LLC.
37568  *
37569  * Originally Released Under LGPL - original licence link has changed is not relivant.
37570  *
37571  * Fork - LGPL
37572  * <script type="text/javascript">
37573  */
37574 /**
37575  * @class Roo.TabPanel
37576  * @extends Roo.util.Observable
37577  * A lightweight tab container.
37578  * <br><br>
37579  * Usage:
37580  * <pre><code>
37581 // basic tabs 1, built from existing content
37582 var tabs = new Roo.TabPanel("tabs1");
37583 tabs.addTab("script", "View Script");
37584 tabs.addTab("markup", "View Markup");
37585 tabs.activate("script");
37586
37587 // more advanced tabs, built from javascript
37588 var jtabs = new Roo.TabPanel("jtabs");
37589 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37590
37591 // set up the UpdateManager
37592 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37593 var updater = tab2.getUpdateManager();
37594 updater.setDefaultUrl("ajax1.htm");
37595 tab2.on('activate', updater.refresh, updater, true);
37596
37597 // Use setUrl for Ajax loading
37598 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37599 tab3.setUrl("ajax2.htm", null, true);
37600
37601 // Disabled tab
37602 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37603 tab4.disable();
37604
37605 jtabs.activate("jtabs-1");
37606  * </code></pre>
37607  * @constructor
37608  * Create a new TabPanel.
37609  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37610  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37611  */
37612 Roo.bootstrap.panel.Tabs = function(config){
37613     /**
37614     * The container element for this TabPanel.
37615     * @type Roo.Element
37616     */
37617     this.el = Roo.get(config.el);
37618     delete config.el;
37619     if(config){
37620         if(typeof config == "boolean"){
37621             this.tabPosition = config ? "bottom" : "top";
37622         }else{
37623             Roo.apply(this, config);
37624         }
37625     }
37626     
37627     if(this.tabPosition == "bottom"){
37628         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37629         this.el.addClass("roo-tabs-bottom");
37630     }
37631     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37632     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37633     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37634     if(Roo.isIE){
37635         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37636     }
37637     if(this.tabPosition != "bottom"){
37638         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37639          * @type Roo.Element
37640          */
37641         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37642         this.el.addClass("roo-tabs-top");
37643     }
37644     this.items = [];
37645
37646     this.bodyEl.setStyle("position", "relative");
37647
37648     this.active = null;
37649     this.activateDelegate = this.activate.createDelegate(this);
37650
37651     this.addEvents({
37652         /**
37653          * @event tabchange
37654          * Fires when the active tab changes
37655          * @param {Roo.TabPanel} this
37656          * @param {Roo.TabPanelItem} activePanel The new active tab
37657          */
37658         "tabchange": true,
37659         /**
37660          * @event beforetabchange
37661          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37662          * @param {Roo.TabPanel} this
37663          * @param {Object} e Set cancel to true on this object to cancel the tab change
37664          * @param {Roo.TabPanelItem} tab The tab being changed to
37665          */
37666         "beforetabchange" : true
37667     });
37668
37669     Roo.EventManager.onWindowResize(this.onResize, this);
37670     this.cpad = this.el.getPadding("lr");
37671     this.hiddenCount = 0;
37672
37673
37674     // toolbar on the tabbar support...
37675     if (this.toolbar) {
37676         alert("no toolbar support yet");
37677         this.toolbar  = false;
37678         /*
37679         var tcfg = this.toolbar;
37680         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37681         this.toolbar = new Roo.Toolbar(tcfg);
37682         if (Roo.isSafari) {
37683             var tbl = tcfg.container.child('table', true);
37684             tbl.setAttribute('width', '100%');
37685         }
37686         */
37687         
37688     }
37689    
37690
37691
37692     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37693 };
37694
37695 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37696     /*
37697      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37698      */
37699     tabPosition : "top",
37700     /*
37701      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37702      */
37703     currentTabWidth : 0,
37704     /*
37705      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37706      */
37707     minTabWidth : 40,
37708     /*
37709      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37710      */
37711     maxTabWidth : 250,
37712     /*
37713      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37714      */
37715     preferredTabWidth : 175,
37716     /*
37717      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37718      */
37719     resizeTabs : false,
37720     /*
37721      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37722      */
37723     monitorResize : true,
37724     /*
37725      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37726      */
37727     toolbar : false,
37728
37729     /**
37730      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37731      * @param {String} id The id of the div to use <b>or create</b>
37732      * @param {String} text The text for the tab
37733      * @param {String} content (optional) Content to put in the TabPanelItem body
37734      * @param {Boolean} closable (optional) True to create a close icon on the tab
37735      * @return {Roo.TabPanelItem} The created TabPanelItem
37736      */
37737     addTab : function(id, text, content, closable, tpl)
37738     {
37739         var item = new Roo.bootstrap.panel.TabItem({
37740             panel: this,
37741             id : id,
37742             text : text,
37743             closable : closable,
37744             tpl : tpl
37745         });
37746         this.addTabItem(item);
37747         if(content){
37748             item.setContent(content);
37749         }
37750         return item;
37751     },
37752
37753     /**
37754      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37755      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37756      * @return {Roo.TabPanelItem}
37757      */
37758     getTab : function(id){
37759         return this.items[id];
37760     },
37761
37762     /**
37763      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37764      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37765      */
37766     hideTab : function(id){
37767         var t = this.items[id];
37768         if(!t.isHidden()){
37769            t.setHidden(true);
37770            this.hiddenCount++;
37771            this.autoSizeTabs();
37772         }
37773     },
37774
37775     /**
37776      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37777      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37778      */
37779     unhideTab : function(id){
37780         var t = this.items[id];
37781         if(t.isHidden()){
37782            t.setHidden(false);
37783            this.hiddenCount--;
37784            this.autoSizeTabs();
37785         }
37786     },
37787
37788     /**
37789      * Adds an existing {@link Roo.TabPanelItem}.
37790      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37791      */
37792     addTabItem : function(item){
37793         this.items[item.id] = item;
37794         this.items.push(item);
37795       //  if(this.resizeTabs){
37796     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37797   //         this.autoSizeTabs();
37798 //        }else{
37799 //            item.autoSize();
37800        // }
37801     },
37802
37803     /**
37804      * Removes a {@link Roo.TabPanelItem}.
37805      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37806      */
37807     removeTab : function(id){
37808         var items = this.items;
37809         var tab = items[id];
37810         if(!tab) { return; }
37811         var index = items.indexOf(tab);
37812         if(this.active == tab && items.length > 1){
37813             var newTab = this.getNextAvailable(index);
37814             if(newTab) {
37815                 newTab.activate();
37816             }
37817         }
37818         this.stripEl.dom.removeChild(tab.pnode.dom);
37819         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37820             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37821         }
37822         items.splice(index, 1);
37823         delete this.items[tab.id];
37824         tab.fireEvent("close", tab);
37825         tab.purgeListeners();
37826         this.autoSizeTabs();
37827     },
37828
37829     getNextAvailable : function(start){
37830         var items = this.items;
37831         var index = start;
37832         // look for a next tab that will slide over to
37833         // replace the one being removed
37834         while(index < items.length){
37835             var item = items[++index];
37836             if(item && !item.isHidden()){
37837                 return item;
37838             }
37839         }
37840         // if one isn't found select the previous tab (on the left)
37841         index = start;
37842         while(index >= 0){
37843             var item = items[--index];
37844             if(item && !item.isHidden()){
37845                 return item;
37846             }
37847         }
37848         return null;
37849     },
37850
37851     /**
37852      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37853      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37854      */
37855     disableTab : function(id){
37856         var tab = this.items[id];
37857         if(tab && this.active != tab){
37858             tab.disable();
37859         }
37860     },
37861
37862     /**
37863      * Enables a {@link Roo.TabPanelItem} that is disabled.
37864      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37865      */
37866     enableTab : function(id){
37867         var tab = this.items[id];
37868         tab.enable();
37869     },
37870
37871     /**
37872      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37873      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37874      * @return {Roo.TabPanelItem} The TabPanelItem.
37875      */
37876     activate : function(id){
37877         var tab = this.items[id];
37878         if(!tab){
37879             return null;
37880         }
37881         if(tab == this.active || tab.disabled){
37882             return tab;
37883         }
37884         var e = {};
37885         this.fireEvent("beforetabchange", this, e, tab);
37886         if(e.cancel !== true && !tab.disabled){
37887             if(this.active){
37888                 this.active.hide();
37889             }
37890             this.active = this.items[id];
37891             this.active.show();
37892             this.fireEvent("tabchange", this, this.active);
37893         }
37894         return tab;
37895     },
37896
37897     /**
37898      * Gets the active {@link Roo.TabPanelItem}.
37899      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37900      */
37901     getActiveTab : function(){
37902         return this.active;
37903     },
37904
37905     /**
37906      * Updates the tab body element to fit the height of the container element
37907      * for overflow scrolling
37908      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37909      */
37910     syncHeight : function(targetHeight){
37911         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37912         var bm = this.bodyEl.getMargins();
37913         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37914         this.bodyEl.setHeight(newHeight);
37915         return newHeight;
37916     },
37917
37918     onResize : function(){
37919         if(this.monitorResize){
37920             this.autoSizeTabs();
37921         }
37922     },
37923
37924     /**
37925      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37926      */
37927     beginUpdate : function(){
37928         this.updating = true;
37929     },
37930
37931     /**
37932      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37933      */
37934     endUpdate : function(){
37935         this.updating = false;
37936         this.autoSizeTabs();
37937     },
37938
37939     /**
37940      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37941      */
37942     autoSizeTabs : function(){
37943         var count = this.items.length;
37944         var vcount = count - this.hiddenCount;
37945         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37946             return;
37947         }
37948         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37949         var availWidth = Math.floor(w / vcount);
37950         var b = this.stripBody;
37951         if(b.getWidth() > w){
37952             var tabs = this.items;
37953             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37954             if(availWidth < this.minTabWidth){
37955                 /*if(!this.sleft){    // incomplete scrolling code
37956                     this.createScrollButtons();
37957                 }
37958                 this.showScroll();
37959                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37960             }
37961         }else{
37962             if(this.currentTabWidth < this.preferredTabWidth){
37963                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37964             }
37965         }
37966     },
37967
37968     /**
37969      * Returns the number of tabs in this TabPanel.
37970      * @return {Number}
37971      */
37972      getCount : function(){
37973          return this.items.length;
37974      },
37975
37976     /**
37977      * Resizes all the tabs to the passed width
37978      * @param {Number} The new width
37979      */
37980     setTabWidth : function(width){
37981         this.currentTabWidth = width;
37982         for(var i = 0, len = this.items.length; i < len; i++) {
37983                 if(!this.items[i].isHidden()) {
37984                 this.items[i].setWidth(width);
37985             }
37986         }
37987     },
37988
37989     /**
37990      * Destroys this TabPanel
37991      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37992      */
37993     destroy : function(removeEl){
37994         Roo.EventManager.removeResizeListener(this.onResize, this);
37995         for(var i = 0, len = this.items.length; i < len; i++){
37996             this.items[i].purgeListeners();
37997         }
37998         if(removeEl === true){
37999             this.el.update("");
38000             this.el.remove();
38001         }
38002     },
38003     
38004     createStrip : function(container)
38005     {
38006         var strip = document.createElement("nav");
38007         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38008         container.appendChild(strip);
38009         return strip;
38010     },
38011     
38012     createStripList : function(strip)
38013     {
38014         // div wrapper for retard IE
38015         // returns the "tr" element.
38016         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38017         //'<div class="x-tabs-strip-wrap">'+
38018           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38019           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38020         return strip.firstChild; //.firstChild.firstChild.firstChild;
38021     },
38022     createBody : function(container)
38023     {
38024         var body = document.createElement("div");
38025         Roo.id(body, "tab-body");
38026         //Roo.fly(body).addClass("x-tabs-body");
38027         Roo.fly(body).addClass("tab-content");
38028         container.appendChild(body);
38029         return body;
38030     },
38031     createItemBody :function(bodyEl, id){
38032         var body = Roo.getDom(id);
38033         if(!body){
38034             body = document.createElement("div");
38035             body.id = id;
38036         }
38037         //Roo.fly(body).addClass("x-tabs-item-body");
38038         Roo.fly(body).addClass("tab-pane");
38039          bodyEl.insertBefore(body, bodyEl.firstChild);
38040         return body;
38041     },
38042     /** @private */
38043     createStripElements :  function(stripEl, text, closable, tpl)
38044     {
38045         var td = document.createElement("li"); // was td..
38046         
38047         
38048         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38049         
38050         
38051         stripEl.appendChild(td);
38052         /*if(closable){
38053             td.className = "x-tabs-closable";
38054             if(!this.closeTpl){
38055                 this.closeTpl = new Roo.Template(
38056                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38057                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38058                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
38059                 );
38060             }
38061             var el = this.closeTpl.overwrite(td, {"text": text});
38062             var close = el.getElementsByTagName("div")[0];
38063             var inner = el.getElementsByTagName("em")[0];
38064             return {"el": el, "close": close, "inner": inner};
38065         } else {
38066         */
38067         // not sure what this is..
38068 //            if(!this.tabTpl){
38069                 //this.tabTpl = new Roo.Template(
38070                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38071                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38072                 //);
38073 //                this.tabTpl = new Roo.Template(
38074 //                   '<a href="#">' +
38075 //                   '<span unselectable="on"' +
38076 //                            (this.disableTooltips ? '' : ' title="{text}"') +
38077 //                            ' >{text}</span></a>'
38078 //                );
38079 //                
38080 //            }
38081
38082
38083             var template = tpl || this.tabTpl || false;
38084             
38085             if(!template){
38086                 
38087                 template = new Roo.Template(
38088                    '<a href="#">' +
38089                    '<span unselectable="on"' +
38090                             (this.disableTooltips ? '' : ' title="{text}"') +
38091                             ' >{text}</span></a>'
38092                 );
38093             }
38094             
38095             switch (typeof(template)) {
38096                 case 'object' :
38097                     break;
38098                 case 'string' :
38099                     template = new Roo.Template(template);
38100                     break;
38101                 default :
38102                     break;
38103             }
38104             
38105             var el = template.overwrite(td, {"text": text});
38106             
38107             var inner = el.getElementsByTagName("span")[0];
38108             
38109             return {"el": el, "inner": inner};
38110             
38111     }
38112         
38113     
38114 });
38115
38116 /**
38117  * @class Roo.TabPanelItem
38118  * @extends Roo.util.Observable
38119  * Represents an individual item (tab plus body) in a TabPanel.
38120  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38121  * @param {String} id The id of this TabPanelItem
38122  * @param {String} text The text for the tab of this TabPanelItem
38123  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38124  */
38125 Roo.bootstrap.panel.TabItem = function(config){
38126     /**
38127      * The {@link Roo.TabPanel} this TabPanelItem belongs to
38128      * @type Roo.TabPanel
38129      */
38130     this.tabPanel = config.panel;
38131     /**
38132      * The id for this TabPanelItem
38133      * @type String
38134      */
38135     this.id = config.id;
38136     /** @private */
38137     this.disabled = false;
38138     /** @private */
38139     this.text = config.text;
38140     /** @private */
38141     this.loaded = false;
38142     this.closable = config.closable;
38143
38144     /**
38145      * The body element for this TabPanelItem.
38146      * @type Roo.Element
38147      */
38148     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38149     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38150     this.bodyEl.setStyle("display", "block");
38151     this.bodyEl.setStyle("zoom", "1");
38152     //this.hideAction();
38153
38154     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38155     /** @private */
38156     this.el = Roo.get(els.el);
38157     this.inner = Roo.get(els.inner, true);
38158     this.textEl = Roo.get(this.el.dom.firstChild, true);
38159     this.pnode = Roo.get(els.el.parentNode, true);
38160 //    this.el.on("mousedown", this.onTabMouseDown, this);
38161     this.el.on("click", this.onTabClick, this);
38162     /** @private */
38163     if(config.closable){
38164         var c = Roo.get(els.close, true);
38165         c.dom.title = this.closeText;
38166         c.addClassOnOver("close-over");
38167         c.on("click", this.closeClick, this);
38168      }
38169
38170     this.addEvents({
38171          /**
38172          * @event activate
38173          * Fires when this tab becomes the active tab.
38174          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38175          * @param {Roo.TabPanelItem} this
38176          */
38177         "activate": true,
38178         /**
38179          * @event beforeclose
38180          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38181          * @param {Roo.TabPanelItem} this
38182          * @param {Object} e Set cancel to true on this object to cancel the close.
38183          */
38184         "beforeclose": true,
38185         /**
38186          * @event close
38187          * Fires when this tab is closed.
38188          * @param {Roo.TabPanelItem} this
38189          */
38190          "close": true,
38191         /**
38192          * @event deactivate
38193          * Fires when this tab is no longer the active tab.
38194          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38195          * @param {Roo.TabPanelItem} this
38196          */
38197          "deactivate" : true
38198     });
38199     this.hidden = false;
38200
38201     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38202 };
38203
38204 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38205            {
38206     purgeListeners : function(){
38207        Roo.util.Observable.prototype.purgeListeners.call(this);
38208        this.el.removeAllListeners();
38209     },
38210     /**
38211      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38212      */
38213     show : function(){
38214         this.pnode.addClass("active");
38215         this.showAction();
38216         if(Roo.isOpera){
38217             this.tabPanel.stripWrap.repaint();
38218         }
38219         this.fireEvent("activate", this.tabPanel, this);
38220     },
38221
38222     /**
38223      * Returns true if this tab is the active tab.
38224      * @return {Boolean}
38225      */
38226     isActive : function(){
38227         return this.tabPanel.getActiveTab() == this;
38228     },
38229
38230     /**
38231      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38232      */
38233     hide : function(){
38234         this.pnode.removeClass("active");
38235         this.hideAction();
38236         this.fireEvent("deactivate", this.tabPanel, this);
38237     },
38238
38239     hideAction : function(){
38240         this.bodyEl.hide();
38241         this.bodyEl.setStyle("position", "absolute");
38242         this.bodyEl.setLeft("-20000px");
38243         this.bodyEl.setTop("-20000px");
38244     },
38245
38246     showAction : function(){
38247         this.bodyEl.setStyle("position", "relative");
38248         this.bodyEl.setTop("");
38249         this.bodyEl.setLeft("");
38250         this.bodyEl.show();
38251     },
38252
38253     /**
38254      * Set the tooltip for the tab.
38255      * @param {String} tooltip The tab's tooltip
38256      */
38257     setTooltip : function(text){
38258         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38259             this.textEl.dom.qtip = text;
38260             this.textEl.dom.removeAttribute('title');
38261         }else{
38262             this.textEl.dom.title = text;
38263         }
38264     },
38265
38266     onTabClick : function(e){
38267         e.preventDefault();
38268         this.tabPanel.activate(this.id);
38269     },
38270
38271     onTabMouseDown : function(e){
38272         e.preventDefault();
38273         this.tabPanel.activate(this.id);
38274     },
38275 /*
38276     getWidth : function(){
38277         return this.inner.getWidth();
38278     },
38279
38280     setWidth : function(width){
38281         var iwidth = width - this.pnode.getPadding("lr");
38282         this.inner.setWidth(iwidth);
38283         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38284         this.pnode.setWidth(width);
38285     },
38286 */
38287     /**
38288      * Show or hide the tab
38289      * @param {Boolean} hidden True to hide or false to show.
38290      */
38291     setHidden : function(hidden){
38292         this.hidden = hidden;
38293         this.pnode.setStyle("display", hidden ? "none" : "");
38294     },
38295
38296     /**
38297      * Returns true if this tab is "hidden"
38298      * @return {Boolean}
38299      */
38300     isHidden : function(){
38301         return this.hidden;
38302     },
38303
38304     /**
38305      * Returns the text for this tab
38306      * @return {String}
38307      */
38308     getText : function(){
38309         return this.text;
38310     },
38311     /*
38312     autoSize : function(){
38313         //this.el.beginMeasure();
38314         this.textEl.setWidth(1);
38315         /*
38316          *  #2804 [new] Tabs in Roojs
38317          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38318          */
38319         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38320         //this.el.endMeasure();
38321     //},
38322
38323     /**
38324      * Sets the text for the tab (Note: this also sets the tooltip text)
38325      * @param {String} text The tab's text and tooltip
38326      */
38327     setText : function(text){
38328         this.text = text;
38329         this.textEl.update(text);
38330         this.setTooltip(text);
38331         //if(!this.tabPanel.resizeTabs){
38332         //    this.autoSize();
38333         //}
38334     },
38335     /**
38336      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38337      */
38338     activate : function(){
38339         this.tabPanel.activate(this.id);
38340     },
38341
38342     /**
38343      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38344      */
38345     disable : function(){
38346         if(this.tabPanel.active != this){
38347             this.disabled = true;
38348             this.pnode.addClass("disabled");
38349         }
38350     },
38351
38352     /**
38353      * Enables this TabPanelItem if it was previously disabled.
38354      */
38355     enable : function(){
38356         this.disabled = false;
38357         this.pnode.removeClass("disabled");
38358     },
38359
38360     /**
38361      * Sets the content for this TabPanelItem.
38362      * @param {String} content The content
38363      * @param {Boolean} loadScripts true to look for and load scripts
38364      */
38365     setContent : function(content, loadScripts){
38366         this.bodyEl.update(content, loadScripts);
38367     },
38368
38369     /**
38370      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38371      * @return {Roo.UpdateManager} The UpdateManager
38372      */
38373     getUpdateManager : function(){
38374         return this.bodyEl.getUpdateManager();
38375     },
38376
38377     /**
38378      * Set a URL to be used to load the content for this TabPanelItem.
38379      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38380      * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
38381      * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
38382      * @return {Roo.UpdateManager} The UpdateManager
38383      */
38384     setUrl : function(url, params, loadOnce){
38385         if(this.refreshDelegate){
38386             this.un('activate', this.refreshDelegate);
38387         }
38388         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38389         this.on("activate", this.refreshDelegate);
38390         return this.bodyEl.getUpdateManager();
38391     },
38392
38393     /** @private */
38394     _handleRefresh : function(url, params, loadOnce){
38395         if(!loadOnce || !this.loaded){
38396             var updater = this.bodyEl.getUpdateManager();
38397             updater.update(url, params, this._setLoaded.createDelegate(this));
38398         }
38399     },
38400
38401     /**
38402      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38403      *   Will fail silently if the setUrl method has not been called.
38404      *   This does not activate the panel, just updates its content.
38405      */
38406     refresh : function(){
38407         if(this.refreshDelegate){
38408            this.loaded = false;
38409            this.refreshDelegate();
38410         }
38411     },
38412
38413     /** @private */
38414     _setLoaded : function(){
38415         this.loaded = true;
38416     },
38417
38418     /** @private */
38419     closeClick : function(e){
38420         var o = {};
38421         e.stopEvent();
38422         this.fireEvent("beforeclose", this, o);
38423         if(o.cancel !== true){
38424             this.tabPanel.removeTab(this.id);
38425         }
38426     },
38427     /**
38428      * The text displayed in the tooltip for the close icon.
38429      * @type String
38430      */
38431     closeText : "Close this tab"
38432 });
38433 /**
38434 *    This script refer to:
38435 *    Title: International Telephone Input
38436 *    Author: Jack O'Connor
38437 *    Code version:  v12.1.12
38438 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38439 **/
38440
38441 Roo.bootstrap.PhoneInputData = function() {
38442     var d = [
38443       [
38444         "Afghanistan (‫افغانستان‬‎)",
38445         "af",
38446         "93"
38447       ],
38448       [
38449         "Albania (Shqipëri)",
38450         "al",
38451         "355"
38452       ],
38453       [
38454         "Algeria (‫الجزائر‬‎)",
38455         "dz",
38456         "213"
38457       ],
38458       [
38459         "American Samoa",
38460         "as",
38461         "1684"
38462       ],
38463       [
38464         "Andorra",
38465         "ad",
38466         "376"
38467       ],
38468       [
38469         "Angola",
38470         "ao",
38471         "244"
38472       ],
38473       [
38474         "Anguilla",
38475         "ai",
38476         "1264"
38477       ],
38478       [
38479         "Antigua and Barbuda",
38480         "ag",
38481         "1268"
38482       ],
38483       [
38484         "Argentina",
38485         "ar",
38486         "54"
38487       ],
38488       [
38489         "Armenia (Հայաստան)",
38490         "am",
38491         "374"
38492       ],
38493       [
38494         "Aruba",
38495         "aw",
38496         "297"
38497       ],
38498       [
38499         "Australia",
38500         "au",
38501         "61",
38502         0
38503       ],
38504       [
38505         "Austria (Österreich)",
38506         "at",
38507         "43"
38508       ],
38509       [
38510         "Azerbaijan (Azərbaycan)",
38511         "az",
38512         "994"
38513       ],
38514       [
38515         "Bahamas",
38516         "bs",
38517         "1242"
38518       ],
38519       [
38520         "Bahrain (‫البحرين‬‎)",
38521         "bh",
38522         "973"
38523       ],
38524       [
38525         "Bangladesh (বাংলাদেশ)",
38526         "bd",
38527         "880"
38528       ],
38529       [
38530         "Barbados",
38531         "bb",
38532         "1246"
38533       ],
38534       [
38535         "Belarus (Беларусь)",
38536         "by",
38537         "375"
38538       ],
38539       [
38540         "Belgium (België)",
38541         "be",
38542         "32"
38543       ],
38544       [
38545         "Belize",
38546         "bz",
38547         "501"
38548       ],
38549       [
38550         "Benin (Bénin)",
38551         "bj",
38552         "229"
38553       ],
38554       [
38555         "Bermuda",
38556         "bm",
38557         "1441"
38558       ],
38559       [
38560         "Bhutan (འབྲུག)",
38561         "bt",
38562         "975"
38563       ],
38564       [
38565         "Bolivia",
38566         "bo",
38567         "591"
38568       ],
38569       [
38570         "Bosnia and Herzegovina (Босна и Херцеговина)",
38571         "ba",
38572         "387"
38573       ],
38574       [
38575         "Botswana",
38576         "bw",
38577         "267"
38578       ],
38579       [
38580         "Brazil (Brasil)",
38581         "br",
38582         "55"
38583       ],
38584       [
38585         "British Indian Ocean Territory",
38586         "io",
38587         "246"
38588       ],
38589       [
38590         "British Virgin Islands",
38591         "vg",
38592         "1284"
38593       ],
38594       [
38595         "Brunei",
38596         "bn",
38597         "673"
38598       ],
38599       [
38600         "Bulgaria (България)",
38601         "bg",
38602         "359"
38603       ],
38604       [
38605         "Burkina Faso",
38606         "bf",
38607         "226"
38608       ],
38609       [
38610         "Burundi (Uburundi)",
38611         "bi",
38612         "257"
38613       ],
38614       [
38615         "Cambodia (កម្ពុជា)",
38616         "kh",
38617         "855"
38618       ],
38619       [
38620         "Cameroon (Cameroun)",
38621         "cm",
38622         "237"
38623       ],
38624       [
38625         "Canada",
38626         "ca",
38627         "1",
38628         1,
38629         ["204", "226", "236", "249", "250", "289", "306", "343", "365", "387", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "672", "705", "709", "742", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905"]
38630       ],
38631       [
38632         "Cape Verde (Kabu Verdi)",
38633         "cv",
38634         "238"
38635       ],
38636       [
38637         "Caribbean Netherlands",
38638         "bq",
38639         "599",
38640         1
38641       ],
38642       [
38643         "Cayman Islands",
38644         "ky",
38645         "1345"
38646       ],
38647       [
38648         "Central African Republic (République centrafricaine)",
38649         "cf",
38650         "236"
38651       ],
38652       [
38653         "Chad (Tchad)",
38654         "td",
38655         "235"
38656       ],
38657       [
38658         "Chile",
38659         "cl",
38660         "56"
38661       ],
38662       [
38663         "China (中国)",
38664         "cn",
38665         "86"
38666       ],
38667       [
38668         "Christmas Island",
38669         "cx",
38670         "61",
38671         2
38672       ],
38673       [
38674         "Cocos (Keeling) Islands",
38675         "cc",
38676         "61",
38677         1
38678       ],
38679       [
38680         "Colombia",
38681         "co",
38682         "57"
38683       ],
38684       [
38685         "Comoros (‫جزر القمر‬‎)",
38686         "km",
38687         "269"
38688       ],
38689       [
38690         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38691         "cd",
38692         "243"
38693       ],
38694       [
38695         "Congo (Republic) (Congo-Brazzaville)",
38696         "cg",
38697         "242"
38698       ],
38699       [
38700         "Cook Islands",
38701         "ck",
38702         "682"
38703       ],
38704       [
38705         "Costa Rica",
38706         "cr",
38707         "506"
38708       ],
38709       [
38710         "Côte d’Ivoire",
38711         "ci",
38712         "225"
38713       ],
38714       [
38715         "Croatia (Hrvatska)",
38716         "hr",
38717         "385"
38718       ],
38719       [
38720         "Cuba",
38721         "cu",
38722         "53"
38723       ],
38724       [
38725         "Curaçao",
38726         "cw",
38727         "599",
38728         0
38729       ],
38730       [
38731         "Cyprus (Κύπρος)",
38732         "cy",
38733         "357"
38734       ],
38735       [
38736         "Czech Republic (Česká republika)",
38737         "cz",
38738         "420"
38739       ],
38740       [
38741         "Denmark (Danmark)",
38742         "dk",
38743         "45"
38744       ],
38745       [
38746         "Djibouti",
38747         "dj",
38748         "253"
38749       ],
38750       [
38751         "Dominica",
38752         "dm",
38753         "1767"
38754       ],
38755       [
38756         "Dominican Republic (República Dominicana)",
38757         "do",
38758         "1",
38759         2,
38760         ["809", "829", "849"]
38761       ],
38762       [
38763         "Ecuador",
38764         "ec",
38765         "593"
38766       ],
38767       [
38768         "Egypt (‫مصر‬‎)",
38769         "eg",
38770         "20"
38771       ],
38772       [
38773         "El Salvador",
38774         "sv",
38775         "503"
38776       ],
38777       [
38778         "Equatorial Guinea (Guinea Ecuatorial)",
38779         "gq",
38780         "240"
38781       ],
38782       [
38783         "Eritrea",
38784         "er",
38785         "291"
38786       ],
38787       [
38788         "Estonia (Eesti)",
38789         "ee",
38790         "372"
38791       ],
38792       [
38793         "Ethiopia",
38794         "et",
38795         "251"
38796       ],
38797       [
38798         "Falkland Islands (Islas Malvinas)",
38799         "fk",
38800         "500"
38801       ],
38802       [
38803         "Faroe Islands (Føroyar)",
38804         "fo",
38805         "298"
38806       ],
38807       [
38808         "Fiji",
38809         "fj",
38810         "679"
38811       ],
38812       [
38813         "Finland (Suomi)",
38814         "fi",
38815         "358",
38816         0
38817       ],
38818       [
38819         "France",
38820         "fr",
38821         "33"
38822       ],
38823       [
38824         "French Guiana (Guyane française)",
38825         "gf",
38826         "594"
38827       ],
38828       [
38829         "French Polynesia (Polynésie française)",
38830         "pf",
38831         "689"
38832       ],
38833       [
38834         "Gabon",
38835         "ga",
38836         "241"
38837       ],
38838       [
38839         "Gambia",
38840         "gm",
38841         "220"
38842       ],
38843       [
38844         "Georgia (საქართველო)",
38845         "ge",
38846         "995"
38847       ],
38848       [
38849         "Germany (Deutschland)",
38850         "de",
38851         "49"
38852       ],
38853       [
38854         "Ghana (Gaana)",
38855         "gh",
38856         "233"
38857       ],
38858       [
38859         "Gibraltar",
38860         "gi",
38861         "350"
38862       ],
38863       [
38864         "Greece (Ελλάδα)",
38865         "gr",
38866         "30"
38867       ],
38868       [
38869         "Greenland (Kalaallit Nunaat)",
38870         "gl",
38871         "299"
38872       ],
38873       [
38874         "Grenada",
38875         "gd",
38876         "1473"
38877       ],
38878       [
38879         "Guadeloupe",
38880         "gp",
38881         "590",
38882         0
38883       ],
38884       [
38885         "Guam",
38886         "gu",
38887         "1671"
38888       ],
38889       [
38890         "Guatemala",
38891         "gt",
38892         "502"
38893       ],
38894       [
38895         "Guernsey",
38896         "gg",
38897         "44",
38898         1
38899       ],
38900       [
38901         "Guinea (Guinée)",
38902         "gn",
38903         "224"
38904       ],
38905       [
38906         "Guinea-Bissau (Guiné Bissau)",
38907         "gw",
38908         "245"
38909       ],
38910       [
38911         "Guyana",
38912         "gy",
38913         "592"
38914       ],
38915       [
38916         "Haiti",
38917         "ht",
38918         "509"
38919       ],
38920       [
38921         "Honduras",
38922         "hn",
38923         "504"
38924       ],
38925       [
38926         "Hong Kong (香港)",
38927         "hk",
38928         "852"
38929       ],
38930       [
38931         "Hungary (Magyarország)",
38932         "hu",
38933         "36"
38934       ],
38935       [
38936         "Iceland (Ísland)",
38937         "is",
38938         "354"
38939       ],
38940       [
38941         "India (भारत)",
38942         "in",
38943         "91"
38944       ],
38945       [
38946         "Indonesia",
38947         "id",
38948         "62"
38949       ],
38950       [
38951         "Iran (‫ایران‬‎)",
38952         "ir",
38953         "98"
38954       ],
38955       [
38956         "Iraq (‫العراق‬‎)",
38957         "iq",
38958         "964"
38959       ],
38960       [
38961         "Ireland",
38962         "ie",
38963         "353"
38964       ],
38965       [
38966         "Isle of Man",
38967         "im",
38968         "44",
38969         2
38970       ],
38971       [
38972         "Israel (‫ישראל‬‎)",
38973         "il",
38974         "972"
38975       ],
38976       [
38977         "Italy (Italia)",
38978         "it",
38979         "39",
38980         0
38981       ],
38982       [
38983         "Jamaica",
38984         "jm",
38985         "1876"
38986       ],
38987       [
38988         "Japan (日本)",
38989         "jp",
38990         "81"
38991       ],
38992       [
38993         "Jersey",
38994         "je",
38995         "44",
38996         3
38997       ],
38998       [
38999         "Jordan (‫الأردن‬‎)",
39000         "jo",
39001         "962"
39002       ],
39003       [
39004         "Kazakhstan (Казахстан)",
39005         "kz",
39006         "7",
39007         1
39008       ],
39009       [
39010         "Kenya",
39011         "ke",
39012         "254"
39013       ],
39014       [
39015         "Kiribati",
39016         "ki",
39017         "686"
39018       ],
39019       [
39020         "Kosovo",
39021         "xk",
39022         "383"
39023       ],
39024       [
39025         "Kuwait (‫الكويت‬‎)",
39026         "kw",
39027         "965"
39028       ],
39029       [
39030         "Kyrgyzstan (Кыргызстан)",
39031         "kg",
39032         "996"
39033       ],
39034       [
39035         "Laos (ລາວ)",
39036         "la",
39037         "856"
39038       ],
39039       [
39040         "Latvia (Latvija)",
39041         "lv",
39042         "371"
39043       ],
39044       [
39045         "Lebanon (‫لبنان‬‎)",
39046         "lb",
39047         "961"
39048       ],
39049       [
39050         "Lesotho",
39051         "ls",
39052         "266"
39053       ],
39054       [
39055         "Liberia",
39056         "lr",
39057         "231"
39058       ],
39059       [
39060         "Libya (‫ليبيا‬‎)",
39061         "ly",
39062         "218"
39063       ],
39064       [
39065         "Liechtenstein",
39066         "li",
39067         "423"
39068       ],
39069       [
39070         "Lithuania (Lietuva)",
39071         "lt",
39072         "370"
39073       ],
39074       [
39075         "Luxembourg",
39076         "lu",
39077         "352"
39078       ],
39079       [
39080         "Macau (澳門)",
39081         "mo",
39082         "853"
39083       ],
39084       [
39085         "Macedonia (FYROM) (Македонија)",
39086         "mk",
39087         "389"
39088       ],
39089       [
39090         "Madagascar (Madagasikara)",
39091         "mg",
39092         "261"
39093       ],
39094       [
39095         "Malawi",
39096         "mw",
39097         "265"
39098       ],
39099       [
39100         "Malaysia",
39101         "my",
39102         "60"
39103       ],
39104       [
39105         "Maldives",
39106         "mv",
39107         "960"
39108       ],
39109       [
39110         "Mali",
39111         "ml",
39112         "223"
39113       ],
39114       [
39115         "Malta",
39116         "mt",
39117         "356"
39118       ],
39119       [
39120         "Marshall Islands",
39121         "mh",
39122         "692"
39123       ],
39124       [
39125         "Martinique",
39126         "mq",
39127         "596"
39128       ],
39129       [
39130         "Mauritania (‫موريتانيا‬‎)",
39131         "mr",
39132         "222"
39133       ],
39134       [
39135         "Mauritius (Moris)",
39136         "mu",
39137         "230"
39138       ],
39139       [
39140         "Mayotte",
39141         "yt",
39142         "262",
39143         1
39144       ],
39145       [
39146         "Mexico (México)",
39147         "mx",
39148         "52"
39149       ],
39150       [
39151         "Micronesia",
39152         "fm",
39153         "691"
39154       ],
39155       [
39156         "Moldova (Republica Moldova)",
39157         "md",
39158         "373"
39159       ],
39160       [
39161         "Monaco",
39162         "mc",
39163         "377"
39164       ],
39165       [
39166         "Mongolia (Монгол)",
39167         "mn",
39168         "976"
39169       ],
39170       [
39171         "Montenegro (Crna Gora)",
39172         "me",
39173         "382"
39174       ],
39175       [
39176         "Montserrat",
39177         "ms",
39178         "1664"
39179       ],
39180       [
39181         "Morocco (‫المغرب‬‎)",
39182         "ma",
39183         "212",
39184         0
39185       ],
39186       [
39187         "Mozambique (Moçambique)",
39188         "mz",
39189         "258"
39190       ],
39191       [
39192         "Myanmar (Burma) (မြန်မာ)",
39193         "mm",
39194         "95"
39195       ],
39196       [
39197         "Namibia (Namibië)",
39198         "na",
39199         "264"
39200       ],
39201       [
39202         "Nauru",
39203         "nr",
39204         "674"
39205       ],
39206       [
39207         "Nepal (नेपाल)",
39208         "np",
39209         "977"
39210       ],
39211       [
39212         "Netherlands (Nederland)",
39213         "nl",
39214         "31"
39215       ],
39216       [
39217         "New Caledonia (Nouvelle-Calédonie)",
39218         "nc",
39219         "687"
39220       ],
39221       [
39222         "New Zealand",
39223         "nz",
39224         "64"
39225       ],
39226       [
39227         "Nicaragua",
39228         "ni",
39229         "505"
39230       ],
39231       [
39232         "Niger (Nijar)",
39233         "ne",
39234         "227"
39235       ],
39236       [
39237         "Nigeria",
39238         "ng",
39239         "234"
39240       ],
39241       [
39242         "Niue",
39243         "nu",
39244         "683"
39245       ],
39246       [
39247         "Norfolk Island",
39248         "nf",
39249         "672"
39250       ],
39251       [
39252         "North Korea (조선 민주주의 인민 공화국)",
39253         "kp",
39254         "850"
39255       ],
39256       [
39257         "Northern Mariana Islands",
39258         "mp",
39259         "1670"
39260       ],
39261       [
39262         "Norway (Norge)",
39263         "no",
39264         "47",
39265         0
39266       ],
39267       [
39268         "Oman (‫عُمان‬‎)",
39269         "om",
39270         "968"
39271       ],
39272       [
39273         "Pakistan (‫پاکستان‬‎)",
39274         "pk",
39275         "92"
39276       ],
39277       [
39278         "Palau",
39279         "pw",
39280         "680"
39281       ],
39282       [
39283         "Palestine (‫فلسطين‬‎)",
39284         "ps",
39285         "970"
39286       ],
39287       [
39288         "Panama (Panamá)",
39289         "pa",
39290         "507"
39291       ],
39292       [
39293         "Papua New Guinea",
39294         "pg",
39295         "675"
39296       ],
39297       [
39298         "Paraguay",
39299         "py",
39300         "595"
39301       ],
39302       [
39303         "Peru (Perú)",
39304         "pe",
39305         "51"
39306       ],
39307       [
39308         "Philippines",
39309         "ph",
39310         "63"
39311       ],
39312       [
39313         "Poland (Polska)",
39314         "pl",
39315         "48"
39316       ],
39317       [
39318         "Portugal",
39319         "pt",
39320         "351"
39321       ],
39322       [
39323         "Puerto Rico",
39324         "pr",
39325         "1",
39326         3,
39327         ["787", "939"]
39328       ],
39329       [
39330         "Qatar (‫قطر‬‎)",
39331         "qa",
39332         "974"
39333       ],
39334       [
39335         "Réunion (La Réunion)",
39336         "re",
39337         "262",
39338         0
39339       ],
39340       [
39341         "Romania (România)",
39342         "ro",
39343         "40"
39344       ],
39345       [
39346         "Russia (Россия)",
39347         "ru",
39348         "7",
39349         0
39350       ],
39351       [
39352         "Rwanda",
39353         "rw",
39354         "250"
39355       ],
39356       [
39357         "Saint Barthélemy",
39358         "bl",
39359         "590",
39360         1
39361       ],
39362       [
39363         "Saint Helena",
39364         "sh",
39365         "290"
39366       ],
39367       [
39368         "Saint Kitts and Nevis",
39369         "kn",
39370         "1869"
39371       ],
39372       [
39373         "Saint Lucia",
39374         "lc",
39375         "1758"
39376       ],
39377       [
39378         "Saint Martin (Saint-Martin (partie française))",
39379         "mf",
39380         "590",
39381         2
39382       ],
39383       [
39384         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39385         "pm",
39386         "508"
39387       ],
39388       [
39389         "Saint Vincent and the Grenadines",
39390         "vc",
39391         "1784"
39392       ],
39393       [
39394         "Samoa",
39395         "ws",
39396         "685"
39397       ],
39398       [
39399         "San Marino",
39400         "sm",
39401         "378"
39402       ],
39403       [
39404         "São Tomé and Príncipe (São Tomé e Príncipe)",
39405         "st",
39406         "239"
39407       ],
39408       [
39409         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39410         "sa",
39411         "966"
39412       ],
39413       [
39414         "Senegal (Sénégal)",
39415         "sn",
39416         "221"
39417       ],
39418       [
39419         "Serbia (Србија)",
39420         "rs",
39421         "381"
39422       ],
39423       [
39424         "Seychelles",
39425         "sc",
39426         "248"
39427       ],
39428       [
39429         "Sierra Leone",
39430         "sl",
39431         "232"
39432       ],
39433       [
39434         "Singapore",
39435         "sg",
39436         "65"
39437       ],
39438       [
39439         "Sint Maarten",
39440         "sx",
39441         "1721"
39442       ],
39443       [
39444         "Slovakia (Slovensko)",
39445         "sk",
39446         "421"
39447       ],
39448       [
39449         "Slovenia (Slovenija)",
39450         "si",
39451         "386"
39452       ],
39453       [
39454         "Solomon Islands",
39455         "sb",
39456         "677"
39457       ],
39458       [
39459         "Somalia (Soomaaliya)",
39460         "so",
39461         "252"
39462       ],
39463       [
39464         "South Africa",
39465         "za",
39466         "27"
39467       ],
39468       [
39469         "South Korea (대한민국)",
39470         "kr",
39471         "82"
39472       ],
39473       [
39474         "South Sudan (‫جنوب السودان‬‎)",
39475         "ss",
39476         "211"
39477       ],
39478       [
39479         "Spain (España)",
39480         "es",
39481         "34"
39482       ],
39483       [
39484         "Sri Lanka (ශ්‍රී ලංකාව)",
39485         "lk",
39486         "94"
39487       ],
39488       [
39489         "Sudan (‫السودان‬‎)",
39490         "sd",
39491         "249"
39492       ],
39493       [
39494         "Suriname",
39495         "sr",
39496         "597"
39497       ],
39498       [
39499         "Svalbard and Jan Mayen",
39500         "sj",
39501         "47",
39502         1
39503       ],
39504       [
39505         "Swaziland",
39506         "sz",
39507         "268"
39508       ],
39509       [
39510         "Sweden (Sverige)",
39511         "se",
39512         "46"
39513       ],
39514       [
39515         "Switzerland (Schweiz)",
39516         "ch",
39517         "41"
39518       ],
39519       [
39520         "Syria (‫سوريا‬‎)",
39521         "sy",
39522         "963"
39523       ],
39524       [
39525         "Taiwan (台灣)",
39526         "tw",
39527         "886"
39528       ],
39529       [
39530         "Tajikistan",
39531         "tj",
39532         "992"
39533       ],
39534       [
39535         "Tanzania",
39536         "tz",
39537         "255"
39538       ],
39539       [
39540         "Thailand (ไทย)",
39541         "th",
39542         "66"
39543       ],
39544       [
39545         "Timor-Leste",
39546         "tl",
39547         "670"
39548       ],
39549       [
39550         "Togo",
39551         "tg",
39552         "228"
39553       ],
39554       [
39555         "Tokelau",
39556         "tk",
39557         "690"
39558       ],
39559       [
39560         "Tonga",
39561         "to",
39562         "676"
39563       ],
39564       [
39565         "Trinidad and Tobago",
39566         "tt",
39567         "1868"
39568       ],
39569       [
39570         "Tunisia (‫تونس‬‎)",
39571         "tn",
39572         "216"
39573       ],
39574       [
39575         "Turkey (Türkiye)",
39576         "tr",
39577         "90"
39578       ],
39579       [
39580         "Turkmenistan",
39581         "tm",
39582         "993"
39583       ],
39584       [
39585         "Turks and Caicos Islands",
39586         "tc",
39587         "1649"
39588       ],
39589       [
39590         "Tuvalu",
39591         "tv",
39592         "688"
39593       ],
39594       [
39595         "U.S. Virgin Islands",
39596         "vi",
39597         "1340"
39598       ],
39599       [
39600         "Uganda",
39601         "ug",
39602         "256"
39603       ],
39604       [
39605         "Ukraine (Україна)",
39606         "ua",
39607         "380"
39608       ],
39609       [
39610         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39611         "ae",
39612         "971"
39613       ],
39614       [
39615         "United Kingdom",
39616         "gb",
39617         "44",
39618         0
39619       ],
39620       [
39621         "United States",
39622         "us",
39623         "1",
39624         0
39625       ],
39626       [
39627         "Uruguay",
39628         "uy",
39629         "598"
39630       ],
39631       [
39632         "Uzbekistan (Oʻzbekiston)",
39633         "uz",
39634         "998"
39635       ],
39636       [
39637         "Vanuatu",
39638         "vu",
39639         "678"
39640       ],
39641       [
39642         "Vatican City (Città del Vaticano)",
39643         "va",
39644         "39",
39645         1
39646       ],
39647       [
39648         "Venezuela",
39649         "ve",
39650         "58"
39651       ],
39652       [
39653         "Vietnam (Việt Nam)",
39654         "vn",
39655         "84"
39656       ],
39657       [
39658         "Wallis and Futuna (Wallis-et-Futuna)",
39659         "wf",
39660         "681"
39661       ],
39662       [
39663         "Western Sahara (‫الصحراء الغربية‬‎)",
39664         "eh",
39665         "212",
39666         1
39667       ],
39668       [
39669         "Yemen (‫اليمن‬‎)",
39670         "ye",
39671         "967"
39672       ],
39673       [
39674         "Zambia",
39675         "zm",
39676         "260"
39677       ],
39678       [
39679         "Zimbabwe",
39680         "zw",
39681         "263"
39682       ],
39683       [
39684         "Åland Islands",
39685         "ax",
39686         "358",
39687         1
39688       ]
39689   ];
39690   
39691   return d;
39692 }/**
39693 *    This script refer to:
39694 *    Title: International Telephone Input
39695 *    Author: Jack O'Connor
39696 *    Code version:  v12.1.12
39697 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39698 **/
39699
39700 /**
39701  * @class Roo.bootstrap.PhoneInput
39702  * @extends Roo.bootstrap.TriggerField
39703  * An input with International dial-code selection
39704  
39705  * @cfg {String} defaultDialCode default '+852'
39706  * @cfg {Array} preferedCountries default []
39707   
39708  * @constructor
39709  * Create a new PhoneInput.
39710  * @param {Object} config Configuration options
39711  */
39712
39713 Roo.bootstrap.PhoneInput = function(config) {
39714     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39715 };
39716
39717 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39718         
39719         listWidth: undefined,
39720         
39721         selectedClass: 'active',
39722         
39723         invalidClass : "has-warning",
39724         
39725         validClass: 'has-success',
39726         
39727         allowed: '0123456789',
39728         
39729         /**
39730          * @cfg {String} defaultDialCode The default dial code when initializing the input
39731          */
39732         defaultDialCode: '+852',
39733         
39734         /**
39735          * @cfg {Array} preferedCountries A list of iso2 in array (e.g. ['hk','us']). Those related countries will show at the top of the input's choices
39736          */
39737         preferedCountries: false,
39738         
39739         getAutoCreate : function()
39740         {
39741             var data = Roo.bootstrap.PhoneInputData();
39742             var align = this.labelAlign || this.parentLabelAlign();
39743             var id = Roo.id();
39744             
39745             this.allCountries = [];
39746             this.dialCodeMapping = [];
39747             
39748             for (var i = 0; i < data.length; i++) {
39749               var c = data[i];
39750               this.allCountries[i] = {
39751                 name: c[0],
39752                 iso2: c[1],
39753                 dialCode: c[2],
39754                 priority: c[3] || 0,
39755                 areaCodes: c[4] || null
39756               };
39757               this.dialCodeMapping[c[2]] = {
39758                   name: c[0],
39759                   iso2: c[1],
39760                   priority: c[3] || 0,
39761                   areaCodes: c[4] || null
39762               };
39763             }
39764             
39765             var cfg = {
39766                 cls: 'form-group',
39767                 cn: []
39768             };
39769             
39770             var input =  {
39771                 tag: 'input',
39772                 id : id,
39773                 cls : 'form-control tel-input',
39774                 autocomplete: 'new-password'
39775             };
39776             
39777             var hiddenInput = {
39778                 tag: 'input',
39779                 type: 'hidden',
39780                 cls: 'hidden-tel-input'
39781             };
39782             
39783             if (this.name) {
39784                 hiddenInput.name = this.name;
39785             }
39786             
39787             if (this.disabled) {
39788                 input.disabled = true;
39789             }
39790             
39791             var flag_container = {
39792                 tag: 'div',
39793                 cls: 'flag-box',
39794                 cn: [
39795                     {
39796                         tag: 'div',
39797                         cls: 'flag'
39798                     },
39799                     {
39800                         tag: 'div',
39801                         cls: 'caret'
39802                     }
39803                 ]
39804             };
39805             
39806             var box = {
39807                 tag: 'div',
39808                 cls: this.hasFeedback ? 'has-feedback' : '',
39809                 cn: [
39810                     hiddenInput,
39811                     input,
39812                     {
39813                         tag: 'input',
39814                         cls: 'dial-code-holder',
39815                         disabled: true
39816                     }
39817                 ]
39818             };
39819             
39820             var container = {
39821                 cls: 'roo-select2-container input-group',
39822                 cn: [
39823                     flag_container,
39824                     box
39825                 ]
39826             };
39827             
39828             if (this.fieldLabel.length) {
39829                 var indicator = {
39830                     tag: 'i',
39831                     tooltip: 'This field is required'
39832                 };
39833                 
39834                 var label = {
39835                     tag: 'label',
39836                     'for':  id,
39837                     cls: 'control-label',
39838                     cn: []
39839                 };
39840                 
39841                 var label_text = {
39842                     tag: 'span',
39843                     html: this.fieldLabel
39844                 };
39845                 
39846                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39847                 label.cn = [
39848                     indicator,
39849                     label_text
39850                 ];
39851                 
39852                 if(this.indicatorpos == 'right') {
39853                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39854                     label.cn = [
39855                         label_text,
39856                         indicator
39857                     ];
39858                 }
39859                 
39860                 if(align == 'left') {
39861                     container = {
39862                         tag: 'div',
39863                         cn: [
39864                             container
39865                         ]
39866                     };
39867                     
39868                     if(this.labelWidth > 12){
39869                         label.style = "width: " + this.labelWidth + 'px';
39870                     }
39871                     if(this.labelWidth < 13 && this.labelmd == 0){
39872                         this.labelmd = this.labelWidth;
39873                     }
39874                     if(this.labellg > 0){
39875                         label.cls += ' col-lg-' + this.labellg;
39876                         input.cls += ' col-lg-' + (12 - this.labellg);
39877                     }
39878                     if(this.labelmd > 0){
39879                         label.cls += ' col-md-' + this.labelmd;
39880                         container.cls += ' col-md-' + (12 - this.labelmd);
39881                     }
39882                     if(this.labelsm > 0){
39883                         label.cls += ' col-sm-' + this.labelsm;
39884                         container.cls += ' col-sm-' + (12 - this.labelsm);
39885                     }
39886                     if(this.labelxs > 0){
39887                         label.cls += ' col-xs-' + this.labelxs;
39888                         container.cls += ' col-xs-' + (12 - this.labelxs);
39889                     }
39890                 }
39891             }
39892             
39893             cfg.cn = [
39894                 label,
39895                 container
39896             ];
39897             
39898             var settings = this;
39899             
39900             ['xs','sm','md','lg'].map(function(size){
39901                 if (settings[size]) {
39902                     cfg.cls += ' col-' + size + '-' + settings[size];
39903                 }
39904             });
39905             
39906             this.store = new Roo.data.Store({
39907                 proxy : new Roo.data.MemoryProxy({}),
39908                 reader : new Roo.data.JsonReader({
39909                     fields : [
39910                         {
39911                             'name' : 'name',
39912                             'type' : 'string'
39913                         },
39914                         {
39915                             'name' : 'iso2',
39916                             'type' : 'string'
39917                         },
39918                         {
39919                             'name' : 'dialCode',
39920                             'type' : 'string'
39921                         },
39922                         {
39923                             'name' : 'priority',
39924                             'type' : 'string'
39925                         },
39926                         {
39927                             'name' : 'areaCodes',
39928                             'type' : 'string'
39929                         }
39930                     ]
39931                 })
39932             });
39933             
39934             if(!this.preferedCountries) {
39935                 this.preferedCountries = [
39936                     'hk',
39937                     'gb',
39938                     'us'
39939                 ];
39940             }
39941             
39942             var p = this.preferedCountries.reverse();
39943             
39944             if(p) {
39945                 for (var i = 0; i < p.length; i++) {
39946                     for (var j = 0; j < this.allCountries.length; j++) {
39947                         if(this.allCountries[j].iso2 == p[i]) {
39948                             var t = this.allCountries[j];
39949                             this.allCountries.splice(j,1);
39950                             this.allCountries.unshift(t);
39951                         }
39952                     } 
39953                 }
39954             }
39955             
39956             this.store.proxy.data = {
39957                 success: true,
39958                 data: this.allCountries
39959             };
39960             
39961             return cfg;
39962         },
39963         
39964         initEvents : function()
39965         {
39966             this.createList();
39967             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39968             
39969             this.indicator = this.indicatorEl();
39970             this.flag = this.flagEl();
39971             this.dialCodeHolder = this.dialCodeHolderEl();
39972             
39973             this.trigger = this.el.select('div.flag-box',true).first();
39974             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39975             
39976             var _this = this;
39977             
39978             (function(){
39979                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39980                 _this.list.setWidth(lw);
39981             }).defer(100);
39982             
39983             this.list.on('mouseover', this.onViewOver, this);
39984             this.list.on('mousemove', this.onViewMove, this);
39985             this.inputEl().on("keyup", this.onKeyUp, this);
39986             
39987             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39988
39989             this.view = new Roo.View(this.list, this.tpl, {
39990                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39991             });
39992             
39993             this.view.on('click', this.onViewClick, this);
39994             this.setValue(this.defaultDialCode);
39995         },
39996         
39997         onTriggerClick : function(e)
39998         {
39999             Roo.log('trigger click');
40000             if(this.disabled){
40001                 return;
40002             }
40003             
40004             if(this.isExpanded()){
40005                 this.collapse();
40006                 this.hasFocus = false;
40007             }else {
40008                 this.store.load({});
40009                 this.hasFocus = true;
40010                 this.expand();
40011             }
40012         },
40013         
40014         isExpanded : function()
40015         {
40016             return this.list.isVisible();
40017         },
40018         
40019         collapse : function()
40020         {
40021             if(!this.isExpanded()){
40022                 return;
40023             }
40024             this.list.hide();
40025             Roo.get(document).un('mousedown', this.collapseIf, this);
40026             Roo.get(document).un('mousewheel', this.collapseIf, this);
40027             this.fireEvent('collapse', this);
40028             this.validate();
40029         },
40030         
40031         expand : function()
40032         {
40033             Roo.log('expand');
40034
40035             if(this.isExpanded() || !this.hasFocus){
40036                 return;
40037             }
40038             
40039             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40040             this.list.setWidth(lw);
40041             
40042             this.list.show();
40043             this.restrictHeight();
40044             
40045             Roo.get(document).on('mousedown', this.collapseIf, this);
40046             Roo.get(document).on('mousewheel', this.collapseIf, this);
40047             
40048             this.fireEvent('expand', this);
40049         },
40050         
40051         restrictHeight : function()
40052         {
40053             this.list.alignTo(this.inputEl(), this.listAlign);
40054             this.list.alignTo(this.inputEl(), this.listAlign);
40055         },
40056         
40057         onViewOver : function(e, t)
40058         {
40059             if(this.inKeyMode){
40060                 return;
40061             }
40062             var item = this.view.findItemFromChild(t);
40063             
40064             if(item){
40065                 var index = this.view.indexOf(item);
40066                 this.select(index, false);
40067             }
40068         },
40069
40070         // private
40071         onViewClick : function(view, doFocus, el, e)
40072         {
40073             var index = this.view.getSelectedIndexes()[0];
40074             
40075             var r = this.store.getAt(index);
40076             
40077             if(r){
40078                 this.onSelect(r, index);
40079             }
40080             if(doFocus !== false && !this.blockFocus){
40081                 this.inputEl().focus();
40082             }
40083         },
40084         
40085         onViewMove : function(e, t)
40086         {
40087             this.inKeyMode = false;
40088         },
40089         
40090         select : function(index, scrollIntoView)
40091         {
40092             this.selectedIndex = index;
40093             this.view.select(index);
40094             if(scrollIntoView !== false){
40095                 var el = this.view.getNode(index);
40096                 if(el){
40097                     this.list.scrollChildIntoView(el, false);
40098                 }
40099             }
40100         },
40101         
40102         createList : function()
40103         {
40104             this.list = Roo.get(document.body).createChild({
40105                 tag: 'ul',
40106                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40107                 style: 'display:none'
40108             });
40109             
40110             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40111         },
40112         
40113         collapseIf : function(e)
40114         {
40115             var in_combo  = e.within(this.el);
40116             var in_list =  e.within(this.list);
40117             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40118             
40119             if (in_combo || in_list || is_list) {
40120                 return;
40121             }
40122             this.collapse();
40123         },
40124         
40125         onSelect : function(record, index)
40126         {
40127             if(this.fireEvent('beforeselect', this, record, index) !== false){
40128                 
40129                 this.setFlagClass(record.data.iso2);
40130                 this.setDialCode(record.data.dialCode);
40131                 this.hasFocus = false;
40132                 this.collapse();
40133                 this.fireEvent('select', this, record, index);
40134             }
40135         },
40136         
40137         flagEl : function()
40138         {
40139             var flag = this.el.select('div.flag',true).first();
40140             if(!flag){
40141                 return false;
40142             }
40143             return flag;
40144         },
40145         
40146         dialCodeHolderEl : function()
40147         {
40148             var d = this.el.select('input.dial-code-holder',true).first();
40149             if(!d){
40150                 return false;
40151             }
40152             return d;
40153         },
40154         
40155         setDialCode : function(v)
40156         {
40157             this.dialCodeHolder.dom.value = '+'+v;
40158         },
40159         
40160         setFlagClass : function(n)
40161         {
40162             this.flag.dom.className = 'flag '+n;
40163         },
40164         
40165         getValue : function()
40166         {
40167             var v = this.inputEl().getValue();
40168             if(this.dialCodeHolder) {
40169                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40170             }
40171             return v;
40172         },
40173         
40174         setValue : function(v)
40175         {
40176             var d = this.getDialCode(v);
40177             
40178             //invalid dial code
40179             if(v.length == 0 || !d || d.length == 0) {
40180                 if(this.rendered){
40181                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40182                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40183                 }
40184                 return;
40185             }
40186             
40187             //valid dial code
40188             this.setFlagClass(this.dialCodeMapping[d].iso2);
40189             this.setDialCode(d);
40190             this.inputEl().dom.value = v.replace('+'+d,'');
40191             this.hiddenEl().dom.value = this.getValue();
40192             
40193             this.validate();
40194         },
40195         
40196         getDialCode : function(v)
40197         {
40198             v = v ||  '';
40199             
40200             if (v.length == 0) {
40201                 return this.dialCodeHolder.dom.value;
40202             }
40203             
40204             var dialCode = "";
40205             if (v.charAt(0) != "+") {
40206                 return false;
40207             }
40208             var numericChars = "";
40209             for (var i = 1; i < v.length; i++) {
40210               var c = v.charAt(i);
40211               if (!isNaN(c)) {
40212                 numericChars += c;
40213                 if (this.dialCodeMapping[numericChars]) {
40214                   dialCode = v.substr(1, i);
40215                 }
40216                 if (numericChars.length == 4) {
40217                   break;
40218                 }
40219               }
40220             }
40221             return dialCode;
40222         },
40223         
40224         reset : function()
40225         {
40226             this.setValue(this.defaultDialCode);
40227             this.validate();
40228         },
40229         
40230         hiddenEl : function()
40231         {
40232             return this.el.select('input.hidden-tel-input',true).first();
40233         },
40234         
40235         onKeyUp : function(e){
40236             
40237             var k = e.getKey();
40238             var c = e.getCharCode();
40239             
40240             if(
40241                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40242                     this.allowed.indexOf(String.fromCharCode(c)) === -1
40243             ){
40244                 e.stopEvent();
40245             }
40246             
40247             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40248             //     return;
40249             // }
40250             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40251                 e.stopEvent();
40252             }
40253             
40254             this.setValue(this.getValue());
40255         }
40256         
40257 });
40258 /**
40259  * @class Roo.bootstrap.MoneyField
40260  * @extends Roo.bootstrap.ComboBox
40261  * Bootstrap MoneyField class
40262  * 
40263  * @constructor
40264  * Create a new MoneyField.
40265  * @param {Object} config Configuration options
40266  */
40267
40268 Roo.bootstrap.MoneyField = function(config) {
40269     
40270     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40271     
40272 };
40273
40274 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40275     
40276     /**
40277      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40278      */
40279     allowDecimals : true,
40280     /**
40281      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40282      */
40283     decimalSeparator : ".",
40284     /**
40285      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40286      */
40287     decimalPrecision : 0,
40288     /**
40289      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40290      */
40291     allowNegative : true,
40292     /**
40293      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40294      */
40295     allowZero: true,
40296     /**
40297      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40298      */
40299     minValue : Number.NEGATIVE_INFINITY,
40300     /**
40301      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40302      */
40303     maxValue : Number.MAX_VALUE,
40304     /**
40305      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40306      */
40307     minText : "The minimum value for this field is {0}",
40308     /**
40309      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40310      */
40311     maxText : "The maximum value for this field is {0}",
40312     /**
40313      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
40314      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40315      */
40316     nanText : "{0} is not a valid number",
40317     /**
40318      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40319      */
40320     castInt : true,
40321     /**
40322      * @cfg {String} defaults currency of the MoneyField
40323      * value should be in lkey
40324      */
40325     defaultCurrency : false,
40326     /**
40327      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40328      */
40329     thousandsDelimiter : false,
40330     
40331     
40332     inputlg : 9,
40333     inputmd : 9,
40334     inputsm : 9,
40335     inputxs : 6,
40336     
40337     store : false,
40338     
40339     getAutoCreate : function()
40340     {
40341         var align = this.labelAlign || this.parentLabelAlign();
40342         
40343         var id = Roo.id();
40344
40345         var cfg = {
40346             cls: 'form-group',
40347             cn: []
40348         };
40349
40350         var input =  {
40351             tag: 'input',
40352             id : id,
40353             cls : 'form-control roo-money-amount-input',
40354             autocomplete: 'new-password'
40355         };
40356         
40357         var hiddenInput = {
40358             tag: 'input',
40359             type: 'hidden',
40360             id: Roo.id(),
40361             cls: 'hidden-number-input'
40362         };
40363         
40364         if (this.name) {
40365             hiddenInput.name = this.name;
40366         }
40367
40368         if (this.disabled) {
40369             input.disabled = true;
40370         }
40371
40372         var clg = 12 - this.inputlg;
40373         var cmd = 12 - this.inputmd;
40374         var csm = 12 - this.inputsm;
40375         var cxs = 12 - this.inputxs;
40376         
40377         var container = {
40378             tag : 'div',
40379             cls : 'row roo-money-field',
40380             cn : [
40381                 {
40382                     tag : 'div',
40383                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40384                     cn : [
40385                         {
40386                             tag : 'div',
40387                             cls: 'roo-select2-container input-group',
40388                             cn: [
40389                                 {
40390                                     tag : 'input',
40391                                     cls : 'form-control roo-money-currency-input',
40392                                     autocomplete: 'new-password',
40393                                     readOnly : 1,
40394                                     name : this.currencyName
40395                                 },
40396                                 {
40397                                     tag :'span',
40398                                     cls : 'input-group-addon',
40399                                     cn : [
40400                                         {
40401                                             tag: 'span',
40402                                             cls: 'caret'
40403                                         }
40404                                     ]
40405                                 }
40406                             ]
40407                         }
40408                     ]
40409                 },
40410                 {
40411                     tag : 'div',
40412                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40413                     cn : [
40414                         {
40415                             tag: 'div',
40416                             cls: this.hasFeedback ? 'has-feedback' : '',
40417                             cn: [
40418                                 input
40419                             ]
40420                         }
40421                     ]
40422                 }
40423             ]
40424             
40425         };
40426         
40427         if (this.fieldLabel.length) {
40428             var indicator = {
40429                 tag: 'i',
40430                 tooltip: 'This field is required'
40431             };
40432
40433             var label = {
40434                 tag: 'label',
40435                 'for':  id,
40436                 cls: 'control-label',
40437                 cn: []
40438             };
40439
40440             var label_text = {
40441                 tag: 'span',
40442                 html: this.fieldLabel
40443             };
40444
40445             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40446             label.cn = [
40447                 indicator,
40448                 label_text
40449             ];
40450
40451             if(this.indicatorpos == 'right') {
40452                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40453                 label.cn = [
40454                     label_text,
40455                     indicator
40456                 ];
40457             }
40458
40459             if(align == 'left') {
40460                 container = {
40461                     tag: 'div',
40462                     cn: [
40463                         container
40464                     ]
40465                 };
40466
40467                 if(this.labelWidth > 12){
40468                     label.style = "width: " + this.labelWidth + 'px';
40469                 }
40470                 if(this.labelWidth < 13 && this.labelmd == 0){
40471                     this.labelmd = this.labelWidth;
40472                 }
40473                 if(this.labellg > 0){
40474                     label.cls += ' col-lg-' + this.labellg;
40475                     input.cls += ' col-lg-' + (12 - this.labellg);
40476                 }
40477                 if(this.labelmd > 0){
40478                     label.cls += ' col-md-' + this.labelmd;
40479                     container.cls += ' col-md-' + (12 - this.labelmd);
40480                 }
40481                 if(this.labelsm > 0){
40482                     label.cls += ' col-sm-' + this.labelsm;
40483                     container.cls += ' col-sm-' + (12 - this.labelsm);
40484                 }
40485                 if(this.labelxs > 0){
40486                     label.cls += ' col-xs-' + this.labelxs;
40487                     container.cls += ' col-xs-' + (12 - this.labelxs);
40488                 }
40489             }
40490         }
40491
40492         cfg.cn = [
40493             label,
40494             container,
40495             hiddenInput
40496         ];
40497         
40498         var settings = this;
40499
40500         ['xs','sm','md','lg'].map(function(size){
40501             if (settings[size]) {
40502                 cfg.cls += ' col-' + size + '-' + settings[size];
40503             }
40504         });
40505         
40506         return cfg;
40507     },
40508     
40509     initEvents : function()
40510     {
40511         this.indicator = this.indicatorEl();
40512         
40513         this.initCurrencyEvent();
40514         
40515         this.initNumberEvent();
40516     },
40517     
40518     initCurrencyEvent : function()
40519     {
40520         if (!this.store) {
40521             throw "can not find store for combo";
40522         }
40523         
40524         this.store = Roo.factory(this.store, Roo.data);
40525         this.store.parent = this;
40526         
40527         this.createList();
40528         
40529         this.triggerEl = this.el.select('.input-group-addon', true).first();
40530         
40531         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40532         
40533         var _this = this;
40534         
40535         (function(){
40536             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40537             _this.list.setWidth(lw);
40538         }).defer(100);
40539         
40540         this.list.on('mouseover', this.onViewOver, this);
40541         this.list.on('mousemove', this.onViewMove, this);
40542         this.list.on('scroll', this.onViewScroll, this);
40543         
40544         if(!this.tpl){
40545             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40546         }
40547         
40548         this.view = new Roo.View(this.list, this.tpl, {
40549             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40550         });
40551         
40552         this.view.on('click', this.onViewClick, this);
40553         
40554         this.store.on('beforeload', this.onBeforeLoad, this);
40555         this.store.on('load', this.onLoad, this);
40556         this.store.on('loadexception', this.onLoadException, this);
40557         
40558         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40559             "up" : function(e){
40560                 this.inKeyMode = true;
40561                 this.selectPrev();
40562             },
40563
40564             "down" : function(e){
40565                 if(!this.isExpanded()){
40566                     this.onTriggerClick();
40567                 }else{
40568                     this.inKeyMode = true;
40569                     this.selectNext();
40570                 }
40571             },
40572
40573             "enter" : function(e){
40574                 this.collapse();
40575                 
40576                 if(this.fireEvent("specialkey", this, e)){
40577                     this.onViewClick(false);
40578                 }
40579                 
40580                 return true;
40581             },
40582
40583             "esc" : function(e){
40584                 this.collapse();
40585             },
40586
40587             "tab" : function(e){
40588                 this.collapse();
40589                 
40590                 if(this.fireEvent("specialkey", this, e)){
40591                     this.onViewClick(false);
40592                 }
40593                 
40594                 return true;
40595             },
40596
40597             scope : this,
40598
40599             doRelay : function(foo, bar, hname){
40600                 if(hname == 'down' || this.scope.isExpanded()){
40601                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40602                 }
40603                 return true;
40604             },
40605
40606             forceKeyDown: true
40607         });
40608         
40609         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40610         
40611     },
40612     
40613     initNumberEvent : function(e)
40614     {
40615         this.inputEl().on("keydown" , this.fireKey,  this);
40616         this.inputEl().on("focus", this.onFocus,  this);
40617         this.inputEl().on("blur", this.onBlur,  this);
40618         
40619         this.inputEl().relayEvent('keyup', this);
40620         
40621         if(this.indicator){
40622             this.indicator.addClass('invisible');
40623         }
40624  
40625         this.originalValue = this.getValue();
40626         
40627         if(this.validationEvent == 'keyup'){
40628             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40629             this.inputEl().on('keyup', this.filterValidation, this);
40630         }
40631         else if(this.validationEvent !== false){
40632             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40633         }
40634         
40635         if(this.selectOnFocus){
40636             this.on("focus", this.preFocus, this);
40637             
40638         }
40639         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40640             this.inputEl().on("keypress", this.filterKeys, this);
40641         } else {
40642             this.inputEl().relayEvent('keypress', this);
40643         }
40644         
40645         var allowed = "0123456789";
40646         
40647         if(this.allowDecimals){
40648             allowed += this.decimalSeparator;
40649         }
40650         
40651         if(this.allowNegative){
40652             allowed += "-";
40653         }
40654         
40655         if(this.thousandsDelimiter) {
40656             allowed += ",";
40657         }
40658         
40659         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40660         
40661         var keyPress = function(e){
40662             
40663             var k = e.getKey();
40664             
40665             var c = e.getCharCode();
40666             
40667             if(
40668                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40669                     allowed.indexOf(String.fromCharCode(c)) === -1
40670             ){
40671                 e.stopEvent();
40672                 return;
40673             }
40674             
40675             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40676                 return;
40677             }
40678             
40679             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40680                 e.stopEvent();
40681             }
40682         };
40683         
40684         this.inputEl().on("keypress", keyPress, this);
40685         
40686     },
40687     
40688     onTriggerClick : function(e)
40689     {   
40690         if(this.disabled){
40691             return;
40692         }
40693         
40694         this.page = 0;
40695         this.loadNext = false;
40696         
40697         if(this.isExpanded()){
40698             this.collapse();
40699             return;
40700         }
40701         
40702         this.hasFocus = true;
40703         
40704         if(this.triggerAction == 'all') {
40705             this.doQuery(this.allQuery, true);
40706             return;
40707         }
40708         
40709         this.doQuery(this.getRawValue());
40710     },
40711     
40712     getCurrency : function()
40713     {   
40714         var v = this.currencyEl().getValue();
40715         
40716         return v;
40717     },
40718     
40719     restrictHeight : function()
40720     {
40721         this.list.alignTo(this.currencyEl(), this.listAlign);
40722         this.list.alignTo(this.currencyEl(), this.listAlign);
40723     },
40724     
40725     onViewClick : function(view, doFocus, el, e)
40726     {
40727         var index = this.view.getSelectedIndexes()[0];
40728         
40729         var r = this.store.getAt(index);
40730         
40731         if(r){
40732             this.onSelect(r, index);
40733         }
40734     },
40735     
40736     onSelect : function(record, index){
40737         
40738         if(this.fireEvent('beforeselect', this, record, index) !== false){
40739         
40740             this.setFromCurrencyData(index > -1 ? record.data : false);
40741             
40742             this.collapse();
40743             
40744             this.fireEvent('select', this, record, index);
40745         }
40746     },
40747     
40748     setFromCurrencyData : function(o)
40749     {
40750         var currency = '';
40751         
40752         this.lastCurrency = o;
40753         
40754         if (this.currencyField) {
40755             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40756         } else {
40757             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40758         }
40759         
40760         this.lastSelectionText = currency;
40761         
40762         //setting default currency
40763         if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40764             this.setCurrency(this.defaultCurrency);
40765             return;
40766         }
40767         
40768         this.setCurrency(currency);
40769     },
40770     
40771     setFromData : function(o)
40772     {
40773         var c = {};
40774         
40775         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40776         
40777         this.setFromCurrencyData(c);
40778         
40779         var value = '';
40780         
40781         if (this.name) {
40782             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40783         } else {
40784             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40785         }
40786         
40787         this.setValue(value);
40788         
40789     },
40790     
40791     setCurrency : function(v)
40792     {   
40793         this.currencyValue = v;
40794         
40795         if(this.rendered){
40796             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40797             this.validate();
40798         }
40799     },
40800     
40801     setValue : function(v)
40802     {
40803         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40804         
40805         this.value = v;
40806         
40807         if(this.rendered){
40808             
40809             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40810             
40811             this.inputEl().dom.value = (v == '') ? '' :
40812                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40813             
40814             if(!this.allowZero && v === '0') {
40815                 this.hiddenEl().dom.value = '';
40816                 this.inputEl().dom.value = '';
40817             }
40818             
40819             this.validate();
40820         }
40821     },
40822     
40823     getRawValue : function()
40824     {
40825         var v = this.inputEl().getValue();
40826         
40827         return v;
40828     },
40829     
40830     getValue : function()
40831     {
40832         return this.fixPrecision(this.parseValue(this.getRawValue()));
40833     },
40834     
40835     parseValue : function(value)
40836     {
40837         if(this.thousandsDelimiter) {
40838             value += "";
40839             r = new RegExp(",", "g");
40840             value = value.replace(r, "");
40841         }
40842         
40843         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40844         return isNaN(value) ? '' : value;
40845         
40846     },
40847     
40848     fixPrecision : function(value)
40849     {
40850         if(this.thousandsDelimiter) {
40851             value += "";
40852             r = new RegExp(",", "g");
40853             value = value.replace(r, "");
40854         }
40855         
40856         var nan = isNaN(value);
40857         
40858         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40859             return nan ? '' : value;
40860         }
40861         return parseFloat(value).toFixed(this.decimalPrecision);
40862     },
40863     
40864     decimalPrecisionFcn : function(v)
40865     {
40866         return Math.floor(v);
40867     },
40868     
40869     validateValue : function(value)
40870     {
40871         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40872             return false;
40873         }
40874         
40875         var num = this.parseValue(value);
40876         
40877         if(isNaN(num)){
40878             this.markInvalid(String.format(this.nanText, value));
40879             return false;
40880         }
40881         
40882         if(num < this.minValue){
40883             this.markInvalid(String.format(this.minText, this.minValue));
40884             return false;
40885         }
40886         
40887         if(num > this.maxValue){
40888             this.markInvalid(String.format(this.maxText, this.maxValue));
40889             return false;
40890         }
40891         
40892         return true;
40893     },
40894     
40895     validate : function()
40896     {
40897         if(this.disabled || this.allowBlank){
40898             this.markValid();
40899             return true;
40900         }
40901         
40902         var currency = this.getCurrency();
40903         
40904         if(this.validateValue(this.getRawValue()) && currency.length){
40905             this.markValid();
40906             return true;
40907         }
40908         
40909         this.markInvalid();
40910         return false;
40911     },
40912     
40913     getName: function()
40914     {
40915         return this.name;
40916     },
40917     
40918     beforeBlur : function()
40919     {
40920         if(!this.castInt){
40921             return;
40922         }
40923         
40924         var v = this.parseValue(this.getRawValue());
40925         
40926         if(v || v == 0){
40927             this.setValue(v);
40928         }
40929     },
40930     
40931     onBlur : function()
40932     {
40933         this.beforeBlur();
40934         
40935         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40936             //this.el.removeClass(this.focusClass);
40937         }
40938         
40939         this.hasFocus = false;
40940         
40941         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40942             this.validate();
40943         }
40944         
40945         var v = this.getValue();
40946         
40947         if(String(v) !== String(this.startValue)){
40948             this.fireEvent('change', this, v, this.startValue);
40949         }
40950         
40951         this.fireEvent("blur", this);
40952     },
40953     
40954     inputEl : function()
40955     {
40956         return this.el.select('.roo-money-amount-input', true).first();
40957     },
40958     
40959     currencyEl : function()
40960     {
40961         return this.el.select('.roo-money-currency-input', true).first();
40962     },
40963     
40964     hiddenEl : function()
40965     {
40966         return this.el.select('input.hidden-number-input',true).first();
40967     }
40968     
40969 });