less/bootstrap/variables.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         
405     },
406     /**
407      * Hide a component - adds 'hidden' class
408      */
409     hide: function()
410     {
411         if(!this.getVisibilityEl()){
412             return;
413         }
414         
415         this.getVisibilityEl().addClass('hidden');
416         
417     }
418 });
419
420  /*
421  * - LGPL
422  *
423  * Body
424  *
425  */
426
427 /**
428  * @class Roo.bootstrap.Body
429  * @extends Roo.bootstrap.Component
430  * Bootstrap Body class
431  *
432  * @constructor
433  * Create a new body
434  * @param {Object} config The config object
435  */
436
437 Roo.bootstrap.Body = function(config){
438
439     config = config || {};
440
441     Roo.bootstrap.Body.superclass.constructor.call(this, config);
442     this.el = Roo.get(config.el ? config.el : document.body );
443     if (this.cls && this.cls.length) {
444         Roo.get(document.body).addClass(this.cls);
445     }
446 };
447
448 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component,  {
449
450     is_body : true,// just to make sure it's constructed?
451
452         autoCreate : {
453         cls: 'container'
454     },
455     onRender : function(ct, position)
456     {
457        /* Roo.log("Roo.bootstrap.Body - onRender");
458         if (this.cls && this.cls.length) {
459             Roo.get(document.body).addClass(this.cls);
460         }
461         // style??? xttr???
462         */
463     }
464
465
466
467
468 });
469 /*
470  * - LGPL
471  *
472  * button group
473  * 
474  */
475
476
477 /**
478  * @class Roo.bootstrap.ButtonGroup
479  * @extends Roo.bootstrap.Component
480  * Bootstrap ButtonGroup class
481  * @cfg {String} size lg | sm | xs (default empty normal)
482  * @cfg {String} align vertical | justified  (default none)
483  * @cfg {String} direction up | down (default down)
484  * @cfg {Boolean} toolbar false | true
485  * @cfg {Boolean} btn true | false
486  * 
487  * 
488  * @constructor
489  * Create a new Input
490  * @param {Object} config The config object
491  */
492
493 Roo.bootstrap.ButtonGroup = function(config){
494     Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
495 };
496
497 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component,  {
498     
499     size: '',
500     align: '',
501     direction: '',
502     toolbar: false,
503     btn: true,
504
505     getAutoCreate : function(){
506         var cfg = {
507             cls: 'btn-group',
508             html : null
509         };
510         
511         cfg.html = this.html || cfg.html;
512         
513         if (this.toolbar) {
514             cfg = {
515                 cls: 'btn-toolbar',
516                 html: null
517             };
518             
519             return cfg;
520         }
521         
522         if (['vertical','justified'].indexOf(this.align)!==-1) {
523             cfg.cls = 'btn-group-' + this.align;
524             
525             if (this.align == 'justified') {
526                 console.log(this.items);
527             }
528         }
529         
530         if (['lg','sm','xs'].indexOf(this.size)!==-1) {
531             cfg.cls += ' btn-group-' + this.size;
532         }
533         
534         if (this.direction == 'up') {
535             cfg.cls += ' dropup' ;
536         }
537         
538         return cfg;
539     }
540    
541 });
542
543  /*
544  * - LGPL
545  *
546  * button
547  * 
548  */
549
550 /**
551  * @class Roo.bootstrap.Button
552  * @extends Roo.bootstrap.Component
553  * Bootstrap Button class
554  * @cfg {String} html The button content
555  * @cfg {String} weight (default | primary | success | info | warning | danger | link ) default 
556  * @cfg {String} size ( lg | sm | xs)
557  * @cfg {String} tag ( a | input | submit)
558  * @cfg {String} href empty or href
559  * @cfg {Boolean} disabled default false;
560  * @cfg {Boolean} isClose default false;
561  * @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)
562  * @cfg {String} badge text for badge
563  * @cfg {String} theme (default|glow)  
564  * @cfg {Boolean} inverse dark themed version
565  * @cfg {Boolean} toggle is it a slidy toggle button
566  * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
567  * @cfg {String} ontext text for on slidy toggle state
568  * @cfg {String} offtext text for off slidy toggle state
569  * @cfg {Boolean} preventDefault  default true (stop click event triggering the URL if it's a link.)
570  * @cfg {Boolean} removeClass remove the standard class..
571  * @cfg {String} target  target for a href. (_self|_blank|_parent|_top| other)
572  * 
573  * @constructor
574  * Create a new button
575  * @param {Object} config The config object
576  */
577
578
579 Roo.bootstrap.Button = function(config){
580     Roo.bootstrap.Button.superclass.constructor.call(this, config);
581     this.weightClass = ["btn-default", 
582                        "btn-primary", 
583                        "btn-success", 
584                        "btn-info", 
585                        "btn-warning",
586                        "btn-danger",
587                        "btn-link"
588                       ],  
589     this.addEvents({
590         // raw events
591         /**
592          * @event click
593          * When a butotn is pressed
594          * @param {Roo.bootstrap.Button} btn
595          * @param {Roo.EventObject} e
596          */
597         "click" : true,
598          /**
599          * @event toggle
600          * After the button has been toggles
601          * @param {Roo.bootstrap.Button} btn
602          * @param {Roo.EventObject} e
603          * @param {boolean} pressed (also available as button.pressed)
604          */
605         "toggle" : true
606     });
607 };
608
609 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component,  {
610     html: false,
611     active: false,
612     weight: '',
613     size: '',
614     tag: 'button',
615     href: '',
616     disabled: false,
617     isClose: false,
618     glyphicon: '',
619     badge: '',
620     theme: 'default',
621     inverse: false,
622     
623     toggle: false,
624     ontext: 'ON',
625     offtext: 'OFF',
626     defaulton: true,
627     preventDefault: true,
628     removeClass: false,
629     name: false,
630     target: false,
631      
632     pressed : null,
633      
634     
635     getAutoCreate : function(){
636         
637         var cfg = {
638             tag : 'button',
639             cls : 'roo-button',
640             html: ''
641         };
642         
643         if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
644             throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
645             this.tag = 'button';
646         } else {
647             cfg.tag = this.tag;
648         }
649         cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
650         
651         if (this.toggle == true) {
652             cfg={
653                 tag: 'div',
654                 cls: 'slider-frame roo-button',
655                 cn: [
656                     {
657                         tag: 'span',
658                         'data-on-text':'ON',
659                         'data-off-text':'OFF',
660                         cls: 'slider-button',
661                         html: this.offtext
662                     }
663                 ]
664             };
665             
666             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
667                 cfg.cls += ' '+this.weight;
668             }
669             
670             return cfg;
671         }
672         
673         if (this.isClose) {
674             cfg.cls += ' close';
675             
676             cfg["aria-hidden"] = true;
677             
678             cfg.html = "&times;";
679             
680             return cfg;
681         }
682         
683          
684         if (this.theme==='default') {
685             cfg.cls = 'btn roo-button';
686             
687             //if (this.parentType != 'Navbar') {
688             this.weight = this.weight.length ?  this.weight : 'default';
689             //}
690             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
691                 
692                 cfg.cls += ' btn-' + this.weight;
693             }
694         } else if (this.theme==='glow') {
695             
696             cfg.tag = 'a';
697             cfg.cls = 'btn-glow roo-button';
698             
699             if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
700                 
701                 cfg.cls += ' ' + this.weight;
702             }
703         }
704    
705         
706         if (this.inverse) {
707             this.cls += ' inverse';
708         }
709         
710         
711         if (this.active || this.pressed === true) {
712             cfg.cls += ' active';
713         }
714         
715         if (this.disabled) {
716             cfg.disabled = 'disabled';
717         }
718         
719         if (this.items) {
720             Roo.log('changing to ul' );
721             cfg.tag = 'ul';
722             this.glyphicon = 'caret';
723         }
724         
725         cfg.cls += this.size.length ? (' btn-' + this.size) : '';
726          
727         //gsRoo.log(this.parentType);
728         if (this.parentType === 'Navbar' && !this.parent().bar) {
729             Roo.log('changing to li?');
730             
731             cfg.tag = 'li';
732             
733             cfg.cls = '';
734             cfg.cn =  [{
735                 tag : 'a',
736                 cls : 'roo-button',
737                 html : this.html,
738                 href : this.href || '#'
739             }];
740             if (this.menu) {
741                 cfg.cn[0].html = this.html  + ' <span class="caret"></span>';
742                 cfg.cls += ' dropdown';
743             }   
744             
745             delete cfg.html;
746             
747         }
748         
749        cfg.cls += this.parentType === 'Navbar' ?  ' navbar-btn' : '';
750         
751         if (this.glyphicon) {
752             cfg.html = ' ' + cfg.html;
753             
754             cfg.cn = [
755                 {
756                     tag: 'span',
757                     cls: 'glyphicon glyphicon-' + this.glyphicon
758                 }
759             ];
760         }
761         
762         if (this.badge) {
763             cfg.html += ' ';
764             
765             cfg.tag = 'a';
766             
767 //            cfg.cls='btn roo-button';
768             
769             cfg.href=this.href;
770             
771             var value = cfg.html;
772             
773             if(this.glyphicon){
774                 value = {
775                             tag: 'span',
776                             cls: 'glyphicon glyphicon-' + this.glyphicon,
777                             html: this.html
778                         };
779                 
780             }
781             
782             cfg.cn = [
783                 value,
784                 {
785                     tag: 'span',
786                     cls: 'badge',
787                     html: this.badge
788                 }
789             ];
790             
791             cfg.html='';
792         }
793         
794         if (this.menu) {
795             cfg.cls += ' dropdown';
796             cfg.html = typeof(cfg.html) != 'undefined' ?
797                     cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
798         }
799         
800         if (cfg.tag !== 'a' && this.href !== '') {
801             throw "Tag must be a to set href.";
802         } else if (this.href.length > 0) {
803             cfg.href = this.href;
804         }
805         
806         if(this.removeClass){
807             cfg.cls = '';
808         }
809         
810         if(this.target){
811             cfg.target = this.target;
812         }
813         
814         return cfg;
815     },
816     initEvents: function() {
817        // Roo.log('init events?');
818 //        Roo.log(this.el.dom);
819         // add the menu...
820         
821         if (typeof (this.menu) != 'undefined') {
822             this.menu.parentType = this.xtype;
823             this.menu.triggerEl = this.el;
824             this.addxtype(Roo.apply({}, this.menu));
825         }
826
827
828        if (this.el.hasClass('roo-button')) {
829             this.el.on('click', this.onClick, this);
830        } else {
831             this.el.select('.roo-button').on('click', this.onClick, this);
832        }
833        
834        if(this.removeClass){
835            this.el.on('click', this.onClick, this);
836        }
837        
838        this.el.enableDisplayMode();
839         
840     },
841     onClick : function(e)
842     {
843         if (this.disabled) {
844             return;
845         }
846         
847         Roo.log('button on click ');
848         if(this.preventDefault){
849             e.preventDefault();
850         }
851         
852         if (this.pressed === true || this.pressed === false) {
853             this.toggleActive(e);
854         }
855         
856         
857         this.fireEvent('click', this, e);
858     },
859     
860     /**
861      * Enables this button
862      */
863     enable : function()
864     {
865         this.disabled = false;
866         this.el.removeClass('disabled');
867     },
868     
869     /**
870      * Disable this button
871      */
872     disable : function()
873     {
874         this.disabled = true;
875         this.el.addClass('disabled');
876     },
877      /**
878      * sets the active state on/off, 
879      * @param {Boolean} state (optional) Force a particular state
880      */
881     setActive : function(v) {
882         
883         this.el[v ? 'addClass' : 'removeClass']('active');
884         this.pressed = v;
885     },
886      /**
887      * toggles the current active state 
888      */
889     toggleActive : function(e)
890     {
891         this.setActive(!this.pressed);
892         this.fireEvent('toggle', this, e, !this.pressed);
893     },
894      /**
895      * get the current active state
896      * @return {boolean} true if it's active
897      */
898     isActive : function()
899     {
900         return this.el.hasClass('active');
901     },
902     /**
903      * set the text of the first selected button
904      */
905     setText : function(str)
906     {
907         this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
908     },
909     /**
910      * get the text of the first selected button
911      */
912     getText : function()
913     {
914         return this.el.select('.roo-button-text',true).first().dom.innerHTML;
915     },
916     hide: function() {
917        
918      
919         this.el.hide();   
920     },
921     show: function() {
922        
923         this.el.show();   
924     },
925     setWeight : function(str)
926     {
927         this.el.removeClass(this.weightClass);
928         this.el.addClass('btn-' + str);        
929     }
930     
931     
932 });
933
934  /*
935  * - LGPL
936  *
937  * column
938  * 
939  */
940
941 /**
942  * @class Roo.bootstrap.Column
943  * @extends Roo.bootstrap.Component
944  * Bootstrap Column class
945  * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
946  * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
947  * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
948  * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
949  * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
950  * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
951  * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
952  * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
953  *
954  * 
955  * @cfg {Boolean} hidden (true|false) hide the element
956  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
957  * @cfg {String} fa (ban|check|...) font awesome icon
958  * @cfg {Number} fasize (1|2|....) font awsome size
959
960  * @cfg {String} icon (info-sign|check|...) glyphicon name
961
962  * @cfg {String} html content of column.
963  * 
964  * @constructor
965  * Create a new Column
966  * @param {Object} config The config object
967  */
968
969 Roo.bootstrap.Column = function(config){
970     Roo.bootstrap.Column.superclass.constructor.call(this, config);
971 };
972
973 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component,  {
974     
975     xs: false,
976     sm: false,
977     md: false,
978     lg: false,
979     xsoff: false,
980     smoff: false,
981     mdoff: false,
982     lgoff: false,
983     html: '',
984     offset: 0,
985     alert: false,
986     fa: false,
987     icon : false,
988     hidden : false,
989     fasize : 1,
990     
991     getAutoCreate : function(){
992         var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
993         
994         cfg = {
995             tag: 'div',
996             cls: 'column'
997         };
998         
999         var settings=this;
1000         ['xs','sm','md','lg'].map(function(size){
1001             //Roo.log( size + ':' + settings[size]);
1002             
1003             if (settings[size+'off'] !== false) {
1004                 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1005             }
1006             
1007             if (settings[size] === false) {
1008                 return;
1009             }
1010             
1011             if (!settings[size]) { // 0 = hidden
1012                 cfg.cls += ' hidden-' + size;
1013                 return;
1014             }
1015             cfg.cls += ' col-' + size + '-' + settings[size];
1016             
1017         });
1018         
1019         if (this.hidden) {
1020             cfg.cls += ' hidden';
1021         }
1022         
1023         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1024             cfg.cls +=' alert alert-' + this.alert;
1025         }
1026         
1027         
1028         if (this.html.length) {
1029             cfg.html = this.html;
1030         }
1031         if (this.fa) {
1032             var fasize = '';
1033             if (this.fasize > 1) {
1034                 fasize = ' fa-' + this.fasize + 'x';
1035             }
1036             cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1037             
1038             
1039         }
1040         if (this.icon) {
1041             cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' +  (cfg.html || '');
1042         }
1043         
1044         return cfg;
1045     }
1046    
1047 });
1048
1049  
1050
1051  /*
1052  * - LGPL
1053  *
1054  * page container.
1055  * 
1056  */
1057
1058
1059 /**
1060  * @class Roo.bootstrap.Container
1061  * @extends Roo.bootstrap.Component
1062  * Bootstrap Container class
1063  * @cfg {Boolean} jumbotron is it a jumbotron element
1064  * @cfg {String} html content of element
1065  * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1066  * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel  - type - primary/success.....
1067  * @cfg {String} header content of header (for panel)
1068  * @cfg {String} footer content of footer (for panel)
1069  * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1070  * @cfg {String} tag (header|aside|section) type of HTML tag.
1071  * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1072  * @cfg {String} fa font awesome icon
1073  * @cfg {String} icon (info-sign|check|...) glyphicon name
1074  * @cfg {Boolean} hidden (true|false) hide the element
1075  * @cfg {Boolean} expandable (true|false) default false
1076  * @cfg {Boolean} expanded (true|false) default true
1077  * @cfg {String} rheader contet on the right of header
1078  * @cfg {Boolean} clickable (true|false) default false
1079
1080  *     
1081  * @constructor
1082  * Create a new Container
1083  * @param {Object} config The config object
1084  */
1085
1086 Roo.bootstrap.Container = function(config){
1087     Roo.bootstrap.Container.superclass.constructor.call(this, config);
1088     
1089     this.addEvents({
1090         // raw events
1091          /**
1092          * @event expand
1093          * After the panel has been expand
1094          * 
1095          * @param {Roo.bootstrap.Container} this
1096          */
1097         "expand" : true,
1098         /**
1099          * @event collapse
1100          * After the panel has been collapsed
1101          * 
1102          * @param {Roo.bootstrap.Container} this
1103          */
1104         "collapse" : true,
1105         /**
1106          * @event click
1107          * When a element is chick
1108          * @param {Roo.bootstrap.Container} this
1109          * @param {Roo.EventObject} e
1110          */
1111         "click" : true
1112     });
1113 };
1114
1115 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component,  {
1116     
1117     jumbotron : false,
1118     well: '',
1119     panel : '',
1120     header: '',
1121     footer : '',
1122     sticky: '',
1123     tag : false,
1124     alert : false,
1125     fa: false,
1126     icon : false,
1127     expandable : false,
1128     rheader : '',
1129     expanded : true,
1130     clickable: false,
1131   
1132      
1133     getChildContainer : function() {
1134         
1135         if(!this.el){
1136             return false;
1137         }
1138         
1139         if (this.panel.length) {
1140             return this.el.select('.panel-body',true).first();
1141         }
1142         
1143         return this.el;
1144     },
1145     
1146     
1147     getAutoCreate : function(){
1148         
1149         var cfg = {
1150             tag : this.tag || 'div',
1151             html : '',
1152             cls : ''
1153         };
1154         if (this.jumbotron) {
1155             cfg.cls = 'jumbotron';
1156         }
1157         
1158         
1159         
1160         // - this is applied by the parent..
1161         //if (this.cls) {
1162         //    cfg.cls = this.cls + '';
1163         //}
1164         
1165         if (this.sticky.length) {
1166             
1167             var bd = Roo.get(document.body);
1168             if (!bd.hasClass('bootstrap-sticky')) {
1169                 bd.addClass('bootstrap-sticky');
1170                 Roo.select('html',true).setStyle('height', '100%');
1171             }
1172              
1173             cfg.cls += 'bootstrap-sticky-' + this.sticky;
1174         }
1175         
1176         
1177         if (this.well.length) {
1178             switch (this.well) {
1179                 case 'lg':
1180                 case 'sm':
1181                     cfg.cls +=' well well-' +this.well;
1182                     break;
1183                 default:
1184                     cfg.cls +=' well';
1185                     break;
1186             }
1187         }
1188         
1189         if (this.hidden) {
1190             cfg.cls += ' hidden';
1191         }
1192         
1193         
1194         if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1195             cfg.cls +=' alert alert-' + this.alert;
1196         }
1197         
1198         var body = cfg;
1199         
1200         if (this.panel.length) {
1201             cfg.cls += ' panel panel-' + this.panel;
1202             cfg.cn = [];
1203             if (this.header.length) {
1204                 
1205                 var h = [];
1206                 
1207                 if(this.expandable){
1208                     
1209                     cfg.cls = cfg.cls + ' expandable';
1210                     
1211                     h.push({
1212                         tag: 'i',
1213                         cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus') 
1214                     });
1215                     
1216                 }
1217                 
1218                 h.push(
1219                     {
1220                         tag: 'span',
1221                         cls : 'panel-title',
1222                         html : (this.expandable ? '&nbsp;' : '') + this.header
1223                     },
1224                     {
1225                         tag: 'span',
1226                         cls: 'panel-header-right',
1227                         html: this.rheader
1228                     }
1229                 );
1230                 
1231                 cfg.cn.push({
1232                     cls : 'panel-heading',
1233                     style : this.expandable ? 'cursor: pointer' : '',
1234                     cn : h
1235                 });
1236                 
1237             }
1238             
1239             body = false;
1240             cfg.cn.push({
1241                 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1242                 html : this.html
1243             });
1244             
1245             
1246             if (this.footer.length) {
1247                 cfg.cn.push({
1248                     cls : 'panel-footer',
1249                     html : this.footer
1250                     
1251                 });
1252             }
1253             
1254         }
1255         
1256         if (body) {
1257             body.html = this.html || cfg.html;
1258             // prefix with the icons..
1259             if (this.fa) {
1260                 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1261             }
1262             if (this.icon) {
1263                 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1264             }
1265             
1266             
1267         }
1268         if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1269             cfg.cls =  'container';
1270         }
1271         
1272         return cfg;
1273     },
1274     
1275     initEvents: function() 
1276     {
1277         if(this.expandable){
1278             var headerEl = this.headerEl();
1279         
1280             if(headerEl){
1281                 headerEl.on('click', this.onToggleClick, this);
1282             }
1283         }
1284         
1285         if(this.clickable){
1286             this.el.on('click', this.onClick, this);
1287         }
1288         
1289     },
1290     
1291     onToggleClick : function()
1292     {
1293         var headerEl = this.headerEl();
1294         
1295         if(!headerEl){
1296             return;
1297         }
1298         
1299         if(this.expanded){
1300             this.collapse();
1301             return;
1302         }
1303         
1304         this.expand();
1305     },
1306     
1307     expand : function()
1308     {
1309         if(this.fireEvent('expand', this)) {
1310             
1311             this.expanded = true;
1312             
1313             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1314             
1315             this.el.select('.panel-body',true).first().removeClass('hide');
1316             
1317             var toggleEl = this.toggleEl();
1318
1319             if(!toggleEl){
1320                 return;
1321             }
1322
1323             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1324         }
1325         
1326     },
1327     
1328     collapse : function()
1329     {
1330         if(this.fireEvent('collapse', this)) {
1331             
1332             this.expanded = false;
1333             
1334             //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1335             this.el.select('.panel-body',true).first().addClass('hide');
1336         
1337             var toggleEl = this.toggleEl();
1338
1339             if(!toggleEl){
1340                 return;
1341             }
1342
1343             toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1344         }
1345     },
1346     
1347     toggleEl : function()
1348     {
1349         if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1350             return;
1351         }
1352         
1353         return this.el.select('.panel-heading .fa',true).first();
1354     },
1355     
1356     headerEl : function()
1357     {
1358         if(!this.el || !this.panel.length || !this.header.length){
1359             return;
1360         }
1361         
1362         return this.el.select('.panel-heading',true).first()
1363     },
1364     
1365     bodyEl : function()
1366     {
1367         if(!this.el || !this.panel.length){
1368             return;
1369         }
1370         
1371         return this.el.select('.panel-body',true).first()
1372     },
1373     
1374     titleEl : function()
1375     {
1376         if(!this.el || !this.panel.length || !this.header.length){
1377             return;
1378         }
1379         
1380         return this.el.select('.panel-title',true).first();
1381     },
1382     
1383     setTitle : function(v)
1384     {
1385         var titleEl = this.titleEl();
1386         
1387         if(!titleEl){
1388             return;
1389         }
1390         
1391         titleEl.dom.innerHTML = v;
1392     },
1393     
1394     getTitle : function()
1395     {
1396         
1397         var titleEl = this.titleEl();
1398         
1399         if(!titleEl){
1400             return '';
1401         }
1402         
1403         return titleEl.dom.innerHTML;
1404     },
1405     
1406     setRightTitle : function(v)
1407     {
1408         var t = this.el.select('.panel-header-right',true).first();
1409         
1410         if(!t){
1411             return;
1412         }
1413         
1414         t.dom.innerHTML = v;
1415     },
1416     
1417     onClick : function(e)
1418     {
1419         e.preventDefault();
1420         
1421         this.fireEvent('click', this, e);
1422     }
1423 });
1424
1425  /*
1426  * - LGPL
1427  *
1428  * image
1429  * 
1430  */
1431
1432
1433 /**
1434  * @class Roo.bootstrap.Img
1435  * @extends Roo.bootstrap.Component
1436  * Bootstrap Img class
1437  * @cfg {Boolean} imgResponsive false | true
1438  * @cfg {String} border rounded | circle | thumbnail
1439  * @cfg {String} src image source
1440  * @cfg {String} alt image alternative text
1441  * @cfg {String} href a tag href
1442  * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1443  * @cfg {String} xsUrl xs image source
1444  * @cfg {String} smUrl sm image source
1445  * @cfg {String} mdUrl md image source
1446  * @cfg {String} lgUrl lg image source
1447  * 
1448  * @constructor
1449  * Create a new Input
1450  * @param {Object} config The config object
1451  */
1452
1453 Roo.bootstrap.Img = function(config){
1454     Roo.bootstrap.Img.superclass.constructor.call(this, config);
1455     
1456     this.addEvents({
1457         // img events
1458         /**
1459          * @event click
1460          * The img click event for the img.
1461          * @param {Roo.EventObject} e
1462          */
1463         "click" : true
1464     });
1465 };
1466
1467 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component,  {
1468     
1469     imgResponsive: true,
1470     border: '',
1471     src: 'about:blank',
1472     href: false,
1473     target: false,
1474     xsUrl: '',
1475     smUrl: '',
1476     mdUrl: '',
1477     lgUrl: '',
1478
1479     getAutoCreate : function()
1480     {   
1481         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1482             return this.createSingleImg();
1483         }
1484         
1485         var cfg = {
1486             tag: 'div',
1487             cls: 'roo-image-responsive-group',
1488             cn: []
1489         };
1490         var _this = this;
1491         
1492         Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1493             
1494             if(!_this[size + 'Url']){
1495                 return;
1496             }
1497             
1498             var img = {
1499                 tag: 'img',
1500                 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1501                 html: _this.html || cfg.html,
1502                 src: _this[size + 'Url']
1503             };
1504             
1505             img.cls += ' roo-image-responsive-' + size;
1506             
1507             var s = ['xs', 'sm', 'md', 'lg'];
1508             
1509             s.splice(s.indexOf(size), 1);
1510             
1511             Roo.each(s, function(ss){
1512                 img.cls += ' hidden-' + ss;
1513             });
1514             
1515             if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1516                 cfg.cls += ' img-' + _this.border;
1517             }
1518             
1519             if(_this.alt){
1520                 cfg.alt = _this.alt;
1521             }
1522             
1523             if(_this.href){
1524                 var a = {
1525                     tag: 'a',
1526                     href: _this.href,
1527                     cn: [
1528                         img
1529                     ]
1530                 };
1531
1532                 if(this.target){
1533                     a.target = _this.target;
1534                 }
1535             }
1536             
1537             cfg.cn.push((_this.href) ? a : img);
1538             
1539         });
1540         
1541         return cfg;
1542     },
1543     
1544     createSingleImg : function()
1545     {
1546         var cfg = {
1547             tag: 'img',
1548             cls: (this.imgResponsive) ? 'img-responsive' : '',
1549             html : null,
1550             src : 'about:blank'  // just incase src get's set to undefined?!?
1551         };
1552         
1553         cfg.html = this.html || cfg.html;
1554         
1555         cfg.src = this.src || cfg.src;
1556         
1557         if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1558             cfg.cls += ' img-' + this.border;
1559         }
1560         
1561         if(this.alt){
1562             cfg.alt = this.alt;
1563         }
1564         
1565         if(this.href){
1566             var a = {
1567                 tag: 'a',
1568                 href: this.href,
1569                 cn: [
1570                     cfg
1571                 ]
1572             };
1573             
1574             if(this.target){
1575                 a.target = this.target;
1576             }
1577             
1578         }
1579         
1580         return (this.href) ? a : cfg;
1581     },
1582     
1583     initEvents: function() 
1584     {
1585         if(!this.href){
1586             this.el.on('click', this.onClick, this);
1587         }
1588         
1589     },
1590     
1591     onClick : function(e)
1592     {
1593         Roo.log('img onclick');
1594         this.fireEvent('click', this, e);
1595     },
1596     /**
1597      * Sets the url of the image - used to update it
1598      * @param {String} url the url of the image
1599      */
1600     
1601     setSrc : function(url)
1602     {
1603         this.src =  url;
1604         
1605         if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1606             this.el.dom.src =  url;
1607             return;
1608         }
1609         
1610         this.el.select('img', true).first().dom.src =  url;
1611     }
1612     
1613     
1614    
1615 });
1616
1617  /*
1618  * - LGPL
1619  *
1620  * image
1621  * 
1622  */
1623
1624
1625 /**
1626  * @class Roo.bootstrap.Link
1627  * @extends Roo.bootstrap.Component
1628  * Bootstrap Link Class
1629  * @cfg {String} alt image alternative text
1630  * @cfg {String} href a tag href
1631  * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1632  * @cfg {String} html the content of the link.
1633  * @cfg {String} anchor name for the anchor link
1634  * @cfg {String} fa - favicon
1635
1636  * @cfg {Boolean} preventDefault (true | false) default false
1637
1638  * 
1639  * @constructor
1640  * Create a new Input
1641  * @param {Object} config The config object
1642  */
1643
1644 Roo.bootstrap.Link = function(config){
1645     Roo.bootstrap.Link.superclass.constructor.call(this, config);
1646     
1647     this.addEvents({
1648         // img events
1649         /**
1650          * @event click
1651          * The img click event for the img.
1652          * @param {Roo.EventObject} e
1653          */
1654         "click" : true
1655     });
1656 };
1657
1658 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component,  {
1659     
1660     href: false,
1661     target: false,
1662     preventDefault: false,
1663     anchor : false,
1664     alt : false,
1665     fa: false,
1666
1667
1668     getAutoCreate : function()
1669     {
1670         var html = this.html || '';
1671         
1672         if (this.fa !== false) {
1673             html = '<i class="fa fa-' + this.fa + '"></i>';
1674         }
1675         var cfg = {
1676             tag: 'a'
1677         };
1678         // anchor's do not require html/href...
1679         if (this.anchor === false) {
1680             cfg.html = html;
1681             cfg.href = this.href || '#';
1682         } else {
1683             cfg.name = this.anchor;
1684             if (this.html !== false || this.fa !== false) {
1685                 cfg.html = html;
1686             }
1687             if (this.href !== false) {
1688                 cfg.href = this.href;
1689             }
1690         }
1691         
1692         if(this.alt !== false){
1693             cfg.alt = this.alt;
1694         }
1695         
1696         
1697         if(this.target !== false) {
1698             cfg.target = this.target;
1699         }
1700         
1701         return cfg;
1702     },
1703     
1704     initEvents: function() {
1705         
1706         if(!this.href || this.preventDefault){
1707             this.el.on('click', this.onClick, this);
1708         }
1709     },
1710     
1711     onClick : function(e)
1712     {
1713         if(this.preventDefault){
1714             e.preventDefault();
1715         }
1716         //Roo.log('img onclick');
1717         this.fireEvent('click', this, e);
1718     }
1719    
1720 });
1721
1722  /*
1723  * - LGPL
1724  *
1725  * header
1726  * 
1727  */
1728
1729 /**
1730  * @class Roo.bootstrap.Header
1731  * @extends Roo.bootstrap.Component
1732  * Bootstrap Header class
1733  * @cfg {String} html content of header
1734  * @cfg {Number} level (1|2|3|4|5|6) default 1
1735  * 
1736  * @constructor
1737  * Create a new Header
1738  * @param {Object} config The config object
1739  */
1740
1741
1742 Roo.bootstrap.Header  = function(config){
1743     Roo.bootstrap.Header.superclass.constructor.call(this, config);
1744 };
1745
1746 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component,  {
1747     
1748     //href : false,
1749     html : false,
1750     level : 1,
1751     
1752     
1753     
1754     getAutoCreate : function(){
1755         
1756         
1757         
1758         var cfg = {
1759             tag: 'h' + (1 *this.level),
1760             html: this.html || ''
1761         } ;
1762         
1763         return cfg;
1764     }
1765    
1766 });
1767
1768  
1769
1770  /*
1771  * Based on:
1772  * Ext JS Library 1.1.1
1773  * Copyright(c) 2006-2007, Ext JS, LLC.
1774  *
1775  * Originally Released Under LGPL - original licence link has changed is not relivant.
1776  *
1777  * Fork - LGPL
1778  * <script type="text/javascript">
1779  */
1780  
1781 /**
1782  * @class Roo.bootstrap.MenuMgr
1783  * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1784  * @singleton
1785  */
1786 Roo.bootstrap.MenuMgr = function(){
1787    var menus, active, groups = {}, attached = false, lastShow = new Date();
1788
1789    // private - called when first menu is created
1790    function init(){
1791        menus = {};
1792        active = new Roo.util.MixedCollection();
1793        Roo.get(document).addKeyListener(27, function(){
1794            if(active.length > 0){
1795                hideAll();
1796            }
1797        });
1798    }
1799
1800    // private
1801    function hideAll(){
1802        if(active && active.length > 0){
1803            var c = active.clone();
1804            c.each(function(m){
1805                m.hide();
1806            });
1807        }
1808    }
1809
1810    // private
1811    function onHide(m){
1812        active.remove(m);
1813        if(active.length < 1){
1814            Roo.get(document).un("mouseup", onMouseDown);
1815             
1816            attached = false;
1817        }
1818    }
1819
1820    // private
1821    function onShow(m){
1822        var last = active.last();
1823        lastShow = new Date();
1824        active.add(m);
1825        if(!attached){
1826           Roo.get(document).on("mouseup", onMouseDown);
1827            
1828            attached = true;
1829        }
1830        if(m.parentMenu){
1831           //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1832           m.parentMenu.activeChild = m;
1833        }else if(last && last.isVisible()){
1834           //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1835        }
1836    }
1837
1838    // private
1839    function onBeforeHide(m){
1840        if(m.activeChild){
1841            m.activeChild.hide();
1842        }
1843        if(m.autoHideTimer){
1844            clearTimeout(m.autoHideTimer);
1845            delete m.autoHideTimer;
1846        }
1847    }
1848
1849    // private
1850    function onBeforeShow(m){
1851        var pm = m.parentMenu;
1852        if(!pm && !m.allowOtherMenus){
1853            hideAll();
1854        }else if(pm && pm.activeChild && active != m){
1855            pm.activeChild.hide();
1856        }
1857    }
1858
1859    // private this should really trigger on mouseup..
1860    function onMouseDown(e){
1861         Roo.log("on Mouse Up");
1862         
1863         if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1864             Roo.log("MenuManager hideAll");
1865             hideAll();
1866             e.stopEvent();
1867         }
1868         
1869         
1870    }
1871
1872    // private
1873    function onBeforeCheck(mi, state){
1874        if(state){
1875            var g = groups[mi.group];
1876            for(var i = 0, l = g.length; i < l; i++){
1877                if(g[i] != mi){
1878                    g[i].setChecked(false);
1879                }
1880            }
1881        }
1882    }
1883
1884    return {
1885
1886        /**
1887         * Hides all menus that are currently visible
1888         */
1889        hideAll : function(){
1890             hideAll();  
1891        },
1892
1893        // private
1894        register : function(menu){
1895            if(!menus){
1896                init();
1897            }
1898            menus[menu.id] = menu;
1899            menu.on("beforehide", onBeforeHide);
1900            menu.on("hide", onHide);
1901            menu.on("beforeshow", onBeforeShow);
1902            menu.on("show", onShow);
1903            var g = menu.group;
1904            if(g && menu.events["checkchange"]){
1905                if(!groups[g]){
1906                    groups[g] = [];
1907                }
1908                groups[g].push(menu);
1909                menu.on("checkchange", onCheck);
1910            }
1911        },
1912
1913         /**
1914          * Returns a {@link Roo.menu.Menu} object
1915          * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1916          * be used to generate and return a new Menu instance.
1917          */
1918        get : function(menu){
1919            if(typeof menu == "string"){ // menu id
1920                return menus[menu];
1921            }else if(menu.events){  // menu instance
1922                return menu;
1923            }
1924            /*else if(typeof menu.length == 'number'){ // array of menu items?
1925                return new Roo.bootstrap.Menu({items:menu});
1926            }else{ // otherwise, must be a config
1927                return new Roo.bootstrap.Menu(menu);
1928            }
1929            */
1930            return false;
1931        },
1932
1933        // private
1934        unregister : function(menu){
1935            delete menus[menu.id];
1936            menu.un("beforehide", onBeforeHide);
1937            menu.un("hide", onHide);
1938            menu.un("beforeshow", onBeforeShow);
1939            menu.un("show", onShow);
1940            var g = menu.group;
1941            if(g && menu.events["checkchange"]){
1942                groups[g].remove(menu);
1943                menu.un("checkchange", onCheck);
1944            }
1945        },
1946
1947        // private
1948        registerCheckable : function(menuItem){
1949            var g = menuItem.group;
1950            if(g){
1951                if(!groups[g]){
1952                    groups[g] = [];
1953                }
1954                groups[g].push(menuItem);
1955                menuItem.on("beforecheckchange", onBeforeCheck);
1956            }
1957        },
1958
1959        // private
1960        unregisterCheckable : function(menuItem){
1961            var g = menuItem.group;
1962            if(g){
1963                groups[g].remove(menuItem);
1964                menuItem.un("beforecheckchange", onBeforeCheck);
1965            }
1966        }
1967    };
1968 }();/*
1969  * - LGPL
1970  *
1971  * menu
1972  * 
1973  */
1974
1975 /**
1976  * @class Roo.bootstrap.Menu
1977  * @extends Roo.bootstrap.Component
1978  * Bootstrap Menu class - container for MenuItems
1979  * @cfg {String} type (dropdown|treeview|submenu) type of menu
1980  * @cfg {bool} hidden  if the menu should be hidden when rendered.
1981  * @cfg {bool} stopEvent (true|false)  Stop event after trigger press (default true)
1982  * @cfg {bool} isLink (true|false)  the menu has link disable auto expand and collaspe (default false)
1983  * 
1984  * @constructor
1985  * Create a new Menu
1986  * @param {Object} config The config object
1987  */
1988
1989
1990 Roo.bootstrap.Menu = function(config){
1991     Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1992     if (this.registerMenu && this.type != 'treeview')  {
1993         Roo.bootstrap.MenuMgr.register(this);
1994     }
1995     this.addEvents({
1996         /**
1997          * @event beforeshow
1998          * Fires before this menu is displayed
1999          * @param {Roo.menu.Menu} this
2000          */
2001         beforeshow : true,
2002         /**
2003          * @event beforehide
2004          * Fires before this menu is hidden
2005          * @param {Roo.menu.Menu} this
2006          */
2007         beforehide : true,
2008         /**
2009          * @event show
2010          * Fires after this menu is displayed
2011          * @param {Roo.menu.Menu} this
2012          */
2013         show : true,
2014         /**
2015          * @event hide
2016          * Fires after this menu is hidden
2017          * @param {Roo.menu.Menu} this
2018          */
2019         hide : true,
2020         /**
2021          * @event click
2022          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2023          * @param {Roo.menu.Menu} this
2024          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2025          * @param {Roo.EventObject} e
2026          */
2027         click : true,
2028         /**
2029          * @event mouseover
2030          * Fires when the mouse is hovering over this menu
2031          * @param {Roo.menu.Menu} this
2032          * @param {Roo.EventObject} e
2033          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2034          */
2035         mouseover : true,
2036         /**
2037          * @event mouseout
2038          * Fires when the mouse exits this menu
2039          * @param {Roo.menu.Menu} this
2040          * @param {Roo.EventObject} e
2041          * @param {Roo.menu.Item} menuItem The menu item that was clicked
2042          */
2043         mouseout : true,
2044         /**
2045          * @event itemclick
2046          * Fires when a menu item contained in this menu is clicked
2047          * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2048          * @param {Roo.EventObject} e
2049          */
2050         itemclick: true
2051     });
2052     this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2053 };
2054
2055 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component,  {
2056     
2057    /// html : false,
2058     //align : '',
2059     triggerEl : false,  // is this set by component builder? -- it should really be fetched from parent()???
2060     type: false,
2061     /**
2062      * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2063      */
2064     registerMenu : true,
2065     
2066     menuItems :false, // stores the menu items..
2067     
2068     hidden:true,
2069         
2070     parentMenu : false,
2071     
2072     stopEvent : true,
2073     
2074     isLink : false,
2075     
2076     getChildContainer : function() {
2077         return this.el;  
2078     },
2079     
2080     getAutoCreate : function(){
2081          
2082         //if (['right'].indexOf(this.align)!==-1) {
2083         //    cfg.cn[1].cls += ' pull-right'
2084         //}
2085         
2086         
2087         var cfg = {
2088             tag : 'ul',
2089             cls : 'dropdown-menu' ,
2090             style : 'z-index:1000'
2091             
2092         };
2093         
2094         if (this.type === 'submenu') {
2095             cfg.cls = 'submenu active';
2096         }
2097         if (this.type === 'treeview') {
2098             cfg.cls = 'treeview-menu';
2099         }
2100         
2101         return cfg;
2102     },
2103     initEvents : function() {
2104         
2105        // Roo.log("ADD event");
2106        // Roo.log(this.triggerEl.dom);
2107         
2108         this.triggerEl.on('click', this.onTriggerClick, this);
2109         
2110         this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2111         
2112         this.triggerEl.addClass('dropdown-toggle');
2113         
2114         if (Roo.isTouch) {
2115             this.el.on('touchstart'  , this.onTouch, this);
2116         }
2117         this.el.on('click' , this.onClick, this);
2118
2119         this.el.on("mouseover", this.onMouseOver, this);
2120         this.el.on("mouseout", this.onMouseOut, this);
2121         
2122     },
2123     
2124     findTargetItem : function(e)
2125     {
2126         var t = e.getTarget(".dropdown-menu-item", this.el,  true);
2127         if(!t){
2128             return false;
2129         }
2130         //Roo.log(t);         Roo.log(t.id);
2131         if(t && t.id){
2132             //Roo.log(this.menuitems);
2133             return this.menuitems.get(t.id);
2134             
2135             //return this.items.get(t.menuItemId);
2136         }
2137         
2138         return false;
2139     },
2140     
2141     onTouch : function(e) 
2142     {
2143         Roo.log("menu.onTouch");
2144         //e.stopEvent(); this make the user popdown broken
2145         this.onClick(e);
2146     },
2147     
2148     onClick : function(e)
2149     {
2150         Roo.log("menu.onClick");
2151         
2152         var t = this.findTargetItem(e);
2153         if(!t || t.isContainer){
2154             return;
2155         }
2156         Roo.log(e);
2157         /*
2158         if (Roo.isTouch && e.type == 'touchstart' && t.menu  && !t.disabled) {
2159             if(t == this.activeItem && t.shouldDeactivate(e)){
2160                 this.activeItem.deactivate();
2161                 delete this.activeItem;
2162                 return;
2163             }
2164             if(t.canActivate){
2165                 this.setActiveItem(t, true);
2166             }
2167             return;
2168             
2169             
2170         }
2171         */
2172        
2173         Roo.log('pass click event');
2174         
2175         t.onClick(e);
2176         
2177         this.fireEvent("click", this, t, e);
2178         
2179         var _this = this;
2180         
2181         if(!t.href.length || t.href == '#'){
2182             (function() { _this.hide(); }).defer(100);
2183         }
2184         
2185     },
2186     
2187     onMouseOver : function(e){
2188         var t  = this.findTargetItem(e);
2189         //Roo.log(t);
2190         //if(t){
2191         //    if(t.canActivate && !t.disabled){
2192         //        this.setActiveItem(t, true);
2193         //    }
2194         //}
2195         
2196         this.fireEvent("mouseover", this, e, t);
2197     },
2198     isVisible : function(){
2199         return !this.hidden;
2200     },
2201      onMouseOut : function(e){
2202         var t  = this.findTargetItem(e);
2203         
2204         //if(t ){
2205         //    if(t == this.activeItem && t.shouldDeactivate(e)){
2206         //        this.activeItem.deactivate();
2207         //        delete this.activeItem;
2208         //    }
2209         //}
2210         this.fireEvent("mouseout", this, e, t);
2211     },
2212     
2213     
2214     /**
2215      * Displays this menu relative to another element
2216      * @param {String/HTMLElement/Roo.Element} element The element to align to
2217      * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2218      * the element (defaults to this.defaultAlign)
2219      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2220      */
2221     show : function(el, pos, parentMenu){
2222         this.parentMenu = parentMenu;
2223         if(!this.el){
2224             this.render();
2225         }
2226         this.fireEvent("beforeshow", this);
2227         this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2228     },
2229      /**
2230      * Displays this menu at a specific xy position
2231      * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2232      * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2233      */
2234     showAt : function(xy, parentMenu, /* private: */_e){
2235         this.parentMenu = parentMenu;
2236         if(!this.el){
2237             this.render();
2238         }
2239         if(_e !== false){
2240             this.fireEvent("beforeshow", this);
2241             //xy = this.el.adjustForConstraints(xy);
2242         }
2243         
2244         //this.el.show();
2245         this.hideMenuItems();
2246         this.hidden = false;
2247         this.triggerEl.addClass('open');
2248         
2249         // reassign x when hitting right
2250         if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2251             xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2252         }
2253         
2254         // reassign y when hitting bottom
2255         if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2256             xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2257         }
2258         
2259         // but the list may align on trigger left or trigger top... should it be a properity?
2260         
2261         if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2262             this.el.setXY(xy);
2263         }
2264         
2265         this.focus();
2266         this.fireEvent("show", this);
2267     },
2268     
2269     focus : function(){
2270         return;
2271         if(!this.hidden){
2272             this.doFocus.defer(50, this);
2273         }
2274     },
2275
2276     doFocus : function(){
2277         if(!this.hidden){
2278             this.focusEl.focus();
2279         }
2280     },
2281
2282     /**
2283      * Hides this menu and optionally all parent menus
2284      * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2285      */
2286     hide : function(deep)
2287     {
2288         
2289         this.hideMenuItems();
2290         if(this.el && this.isVisible()){
2291             this.fireEvent("beforehide", this);
2292             if(this.activeItem){
2293                 this.activeItem.deactivate();
2294                 this.activeItem = null;
2295             }
2296             this.triggerEl.removeClass('open');;
2297             this.hidden = true;
2298             this.fireEvent("hide", this);
2299         }
2300         if(deep === true && this.parentMenu){
2301             this.parentMenu.hide(true);
2302         }
2303     },
2304     
2305     onTriggerClick : function(e)
2306     {
2307         Roo.log('trigger click');
2308         
2309         var target = e.getTarget();
2310         
2311         Roo.log(target.nodeName.toLowerCase());
2312         
2313         if(target.nodeName.toLowerCase() === 'i'){
2314             e.preventDefault();
2315         }
2316         
2317     },
2318     
2319     onTriggerPress  : function(e)
2320     {
2321         Roo.log('trigger press');
2322         //Roo.log(e.getTarget());
2323        // Roo.log(this.triggerEl.dom);
2324        
2325         // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2326         var pel = Roo.get(e.getTarget());
2327         if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2328             Roo.log('is treeview or dropdown?');
2329             return;
2330         }
2331         
2332         if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2333             return;
2334         }
2335         
2336         if (this.isVisible()) {
2337             Roo.log('hide');
2338             this.hide();
2339         } else {
2340             Roo.log('show');
2341             this.show(this.triggerEl, false, false);
2342         }
2343         
2344         if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2345             e.stopEvent();
2346         }
2347         
2348     },
2349        
2350     
2351     hideMenuItems : function()
2352     {
2353         Roo.log("hide Menu Items");
2354         if (!this.el) { 
2355             return;
2356         }
2357         //$(backdrop).remove()
2358         this.el.select('.open',true).each(function(aa) {
2359             
2360             aa.removeClass('open');
2361           //var parent = getParent($(this))
2362           //var relatedTarget = { relatedTarget: this }
2363           
2364            //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2365           //if (e.isDefaultPrevented()) return
2366            //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2367         });
2368     },
2369     addxtypeChild : function (tree, cntr) {
2370         var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2371           
2372         this.menuitems.add(comp);
2373         return comp;
2374
2375     },
2376     getEl : function()
2377     {
2378         Roo.log(this.el);
2379         return this.el;
2380     },
2381     
2382     clear : function()
2383     {
2384         this.getEl().dom.innerHTML = '';
2385         this.menuitems.clear();
2386     }
2387 });
2388
2389  
2390  /*
2391  * - LGPL
2392  *
2393  * menu item
2394  * 
2395  */
2396
2397
2398 /**
2399  * @class Roo.bootstrap.MenuItem
2400  * @extends Roo.bootstrap.Component
2401  * Bootstrap MenuItem class
2402  * @cfg {String} html the menu label
2403  * @cfg {String} href the link
2404  * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2405  * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2406  * @cfg {Boolean} active  used on sidebars to highlight active itesm
2407  * @cfg {String} fa favicon to show on left of menu item.
2408  * @cfg {Roo.bootsrap.Menu} menu the child menu.
2409  * 
2410  * 
2411  * @constructor
2412  * Create a new MenuItem
2413  * @param {Object} config The config object
2414  */
2415
2416
2417 Roo.bootstrap.MenuItem = function(config){
2418     Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2419     this.addEvents({
2420         // raw events
2421         /**
2422          * @event click
2423          * The raw click event for the entire grid.
2424          * @param {Roo.bootstrap.MenuItem} this
2425          * @param {Roo.EventObject} e
2426          */
2427         "click" : true
2428     });
2429 };
2430
2431 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component,  {
2432     
2433     href : false,
2434     html : false,
2435     preventDefault: false,
2436     isContainer : false,
2437     active : false,
2438     fa: false,
2439     
2440     getAutoCreate : function(){
2441         
2442         if(this.isContainer){
2443             return {
2444                 tag: 'li',
2445                 cls: 'dropdown-menu-item'
2446             };
2447         }
2448         var ctag = {
2449             tag: 'span',
2450             html: 'Link'
2451         };
2452         
2453         var anc = {
2454             tag : 'a',
2455             href : '#',
2456             cn : [  ]
2457         };
2458         
2459         if (this.fa !== false) {
2460             anc.cn.push({
2461                 tag : 'i',
2462                 cls : 'fa fa-' + this.fa
2463             });
2464         }
2465         
2466         anc.cn.push(ctag);
2467         
2468         
2469         var cfg= {
2470             tag: 'li',
2471             cls: 'dropdown-menu-item',
2472             cn: [ anc ]
2473         };
2474         if (this.parent().type == 'treeview') {
2475             cfg.cls = 'treeview-menu';
2476         }
2477         if (this.active) {
2478             cfg.cls += ' active';
2479         }
2480         
2481         
2482         
2483         anc.href = this.href || cfg.cn[0].href ;
2484         ctag.html = this.html || cfg.cn[0].html ;
2485         return cfg;
2486     },
2487     
2488     initEvents: function()
2489     {
2490         if (this.parent().type == 'treeview') {
2491             this.el.select('a').on('click', this.onClick, this);
2492         }
2493         
2494         if (this.menu) {
2495             this.menu.parentType = this.xtype;
2496             this.menu.triggerEl = this.el;
2497             this.menu = this.addxtype(Roo.apply({}, this.menu));
2498         }
2499         
2500     },
2501     onClick : function(e)
2502     {
2503         Roo.log('item on click ');
2504         
2505         if(this.preventDefault){
2506             e.preventDefault();
2507         }
2508         //this.parent().hideMenuItems();
2509         
2510         this.fireEvent('click', this, e);
2511     },
2512     getEl : function()
2513     {
2514         return this.el;
2515     } 
2516 });
2517
2518  
2519
2520  /*
2521  * - LGPL
2522  *
2523  * menu separator
2524  * 
2525  */
2526
2527
2528 /**
2529  * @class Roo.bootstrap.MenuSeparator
2530  * @extends Roo.bootstrap.Component
2531  * Bootstrap MenuSeparator class
2532  * 
2533  * @constructor
2534  * Create a new MenuItem
2535  * @param {Object} config The config object
2536  */
2537
2538
2539 Roo.bootstrap.MenuSeparator = function(config){
2540     Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2541 };
2542
2543 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component,  {
2544     
2545     getAutoCreate : function(){
2546         var cfg = {
2547             cls: 'divider',
2548             tag : 'li'
2549         };
2550         
2551         return cfg;
2552     }
2553    
2554 });
2555
2556  
2557
2558  
2559 /*
2560 * Licence: LGPL
2561 */
2562
2563 /**
2564  * @class Roo.bootstrap.Modal
2565  * @extends Roo.bootstrap.Component
2566  * Bootstrap Modal class
2567  * @cfg {String} title Title of dialog
2568  * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2569  * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method  adn
2570  * @cfg {Boolean} specificTitle default false
2571  * @cfg {Array} buttons Array of buttons or standard button set..
2572  * @cfg {String} buttonPosition (left|right|center) default right
2573  * @cfg {Boolean} animate default true
2574  * @cfg {Boolean} allow_close default true
2575  * @cfg {Boolean} fitwindow default false
2576  * @cfg {String} size (sm|lg) default empty
2577  *
2578  *
2579  * @constructor
2580  * Create a new Modal Dialog
2581  * @param {Object} config The config object
2582  */
2583
2584 Roo.bootstrap.Modal = function(config){
2585     Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2586     this.addEvents({
2587         // raw events
2588         /**
2589          * @event btnclick
2590          * The raw btnclick event for the button
2591          * @param {Roo.EventObject} e
2592          */
2593         "btnclick" : true,
2594         /**
2595          * @event resize
2596          * Fire when dialog resize
2597          * @param {Roo.bootstrap.Modal} this
2598          * @param {Roo.EventObject} e
2599          */
2600         "resize" : true
2601     });
2602     this.buttons = this.buttons || [];
2603
2604     if (this.tmpl) {
2605         this.tmpl = Roo.factory(this.tmpl);
2606     }
2607
2608 };
2609
2610 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component,  {
2611
2612     title : 'test dialog',
2613
2614     buttons : false,
2615
2616     // set on load...
2617
2618     html: false,
2619
2620     tmp: false,
2621
2622     specificTitle: false,
2623
2624     buttonPosition: 'right',
2625
2626     allow_close : true,
2627
2628     animate : true,
2629
2630     fitwindow: false,
2631
2632
2633      // private
2634     dialogEl: false,
2635     bodyEl:  false,
2636     footerEl:  false,
2637     titleEl:  false,
2638     closeEl:  false,
2639
2640     size: '',
2641
2642
2643     onRender : function(ct, position)
2644     {
2645         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2646
2647         if(!this.el){
2648             var cfg = Roo.apply({},  this.getAutoCreate());
2649             cfg.id = Roo.id();
2650             //if(!cfg.name){
2651             //    cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2652             //}
2653             //if (!cfg.name.length) {
2654             //    delete cfg.name;
2655            // }
2656             if (this.cls) {
2657                 cfg.cls += ' ' + this.cls;
2658             }
2659             if (this.style) {
2660                 cfg.style = this.style;
2661             }
2662             this.el = Roo.get(document.body).createChild(cfg, position);
2663         }
2664         //var type = this.el.dom.type;
2665
2666
2667         if(this.tabIndex !== undefined){
2668             this.el.dom.setAttribute('tabIndex', this.tabIndex);
2669         }
2670
2671         this.dialogEl = this.el.select('.modal-dialog',true).first();
2672         this.bodyEl = this.el.select('.modal-body',true).first();
2673         this.closeEl = this.el.select('.modal-header .close', true).first();
2674         this.headerEl = this.el.select('.modal-header',true).first();
2675         this.titleEl = this.el.select('.modal-title',true).first();
2676         this.footerEl = this.el.select('.modal-footer',true).first();
2677
2678         this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2679         
2680         //this.el.addClass("x-dlg-modal");
2681
2682         if (this.buttons.length) {
2683             Roo.each(this.buttons, function(bb) {
2684                 var b = Roo.apply({}, bb);
2685                 b.xns = b.xns || Roo.bootstrap;
2686                 b.xtype = b.xtype || 'Button';
2687                 if (typeof(b.listeners) == 'undefined') {
2688                     b.listeners = { click : this.onButtonClick.createDelegate(this)  };
2689                 }
2690
2691                 var btn = Roo.factory(b);
2692
2693                 btn.render(this.el.select('.modal-footer div').first());
2694
2695             },this);
2696         }
2697         // render the children.
2698         var nitems = [];
2699
2700         if(typeof(this.items) != 'undefined'){
2701             var items = this.items;
2702             delete this.items;
2703
2704             for(var i =0;i < items.length;i++) {
2705                 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2706             }
2707         }
2708
2709         this.items = nitems;
2710
2711         // where are these used - they used to be body/close/footer
2712
2713
2714         this.initEvents();
2715         //this.el.addClass([this.fieldClass, this.cls]);
2716
2717     },
2718
2719     getAutoCreate : function(){
2720
2721
2722         var bdy = {
2723                 cls : 'modal-body',
2724                 html : this.html || ''
2725         };
2726
2727         var title = {
2728             tag: 'h4',
2729             cls : 'modal-title',
2730             html : this.title
2731         };
2732
2733         if(this.specificTitle){
2734             title = this.title;
2735
2736         };
2737
2738         var header = [];
2739         if (this.allow_close) {
2740             header.push({
2741                 tag: 'button',
2742                 cls : 'close',
2743                 html : '&times'
2744             });
2745         }
2746
2747         header.push(title);
2748
2749         var size = '';
2750
2751         if(this.size.length){
2752             size = 'modal-' + this.size;
2753         }
2754
2755         var modal = {
2756             cls: "modal",
2757              cn : [
2758                 {
2759                     cls: "modal-dialog " + size,
2760                     cn : [
2761                         {
2762                             cls : "modal-content",
2763                             cn : [
2764                                 {
2765                                     cls : 'modal-header',
2766                                     cn : header
2767                                 },
2768                                 bdy,
2769                                 {
2770                                     cls : 'modal-footer',
2771                                     cn : [
2772                                         {
2773                                             tag: 'div',
2774                                             cls: 'btn-' + this.buttonPosition
2775                                         }
2776                                     ]
2777
2778                                 }
2779
2780
2781                             ]
2782
2783                         }
2784                     ]
2785
2786                 }
2787             ]
2788         };
2789
2790         if(this.animate){
2791             modal.cls += ' fade';
2792         }
2793
2794         return modal;
2795
2796     },
2797     getChildContainer : function() {
2798
2799          return this.bodyEl;
2800
2801     },
2802     getButtonContainer : function() {
2803          return this.el.select('.modal-footer div',true).first();
2804
2805     },
2806     initEvents : function()
2807     {
2808         if (this.allow_close) {
2809             this.closeEl.on('click', this.hide, this);
2810         }
2811         Roo.EventManager.onWindowResize(this.resize, this, true);
2812
2813
2814     },
2815
2816     resize : function()
2817     {
2818         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),  Roo.lib.Dom.getViewHeight(true));
2819         if (this.fitwindow) {
2820             var w = this.width || Roo.lib.Dom.getViewportWidth(true) - 30;
2821             var h = this.height || Roo.lib.Dom.getViewportHeight(true) - 60;
2822             this.setSize(w,h);
2823         }
2824     },
2825
2826     setSize : function(w,h)
2827     {
2828         if (!w && !h) {
2829             return;
2830         }
2831         this.resizeTo(w,h);
2832     },
2833
2834     show : function() {
2835
2836         if (!this.rendered) {
2837             this.render();
2838         }
2839
2840         //this.el.setStyle('display', 'block');
2841         this.el.removeClass('hideing');        
2842         this.el.addClass('show');
2843  
2844         if(this.animate){  // element has 'fade'  - so stuff happens after .3s ?- not sure why the delay?
2845             var _this = this;
2846             (function(){
2847                 this.el.addClass('in');
2848             }).defer(50, this);
2849         }else{
2850             this.el.addClass('in');
2851
2852         }
2853
2854         // not sure how we can show data in here..
2855         //if (this.tmpl) {
2856         //    this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2857         //}
2858
2859         Roo.get(document.body).addClass("x-body-masked");
2860         
2861         this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true),   Roo.lib.Dom.getViewHeight(true));
2862         this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2863         this.maskEl.addClass('show');
2864         
2865         this.resize();
2866         
2867         this.fireEvent('show', this);
2868
2869         // set zindex here - otherwise it appears to be ignored...
2870         this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2871
2872         (function () {
2873             this.items.forEach( function(e) {
2874                 e.layout ? e.layout() : false;
2875
2876             });
2877         }).defer(100,this);
2878
2879     },
2880     hide : function()
2881     {
2882         if(this.fireEvent("beforehide", this) !== false){
2883             this.maskEl.removeClass('show');
2884             Roo.get(document.body).removeClass("x-body-masked");
2885             this.el.removeClass('in');
2886             this.el.select('.modal-dialog', true).first().setStyle('transform','');
2887
2888             if(this.animate){ // why
2889                 this.el.addClass('hideing');
2890                 (function(){
2891                     if (!this.el.hasClass('hideing')) {
2892                         return; // it's been shown again...
2893                     }
2894                     this.el.removeClass('show');
2895                     this.el.removeClass('hideing');
2896                 }).defer(150,this);
2897                 
2898             }else{
2899                  this.el.removeClass('show');
2900             }
2901             this.fireEvent('hide', this);
2902         }
2903     },
2904     isVisible : function()
2905     {
2906         
2907         return this.el.hasClass('show') && !this.el.hasClass('hideing');
2908         
2909     },
2910
2911     addButton : function(str, cb)
2912     {
2913
2914
2915         var b = Roo.apply({}, { html : str } );
2916         b.xns = b.xns || Roo.bootstrap;
2917         b.xtype = b.xtype || 'Button';
2918         if (typeof(b.listeners) == 'undefined') {
2919             b.listeners = { click : cb.createDelegate(this)  };
2920         }
2921
2922         var btn = Roo.factory(b);
2923
2924         btn.render(this.el.select('.modal-footer div').first());
2925
2926         return btn;
2927
2928     },
2929
2930     setDefaultButton : function(btn)
2931     {
2932         //this.el.select('.modal-footer').()
2933     },
2934     diff : false,
2935
2936     resizeTo: function(w,h)
2937     {
2938         // skip.. ?? why??
2939
2940         this.dialogEl.setWidth(w);
2941         if (this.diff === false) {
2942             this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
2943         }
2944
2945         this.bodyEl.setHeight(h-this.diff);
2946
2947         this.fireEvent('resize', this);
2948
2949     },
2950     setContentSize  : function(w, h)
2951     {
2952
2953     },
2954     onButtonClick: function(btn,e)
2955     {
2956         //Roo.log([a,b,c]);
2957         this.fireEvent('btnclick', btn.name, e);
2958     },
2959      /**
2960      * Set the title of the Dialog
2961      * @param {String} str new Title
2962      */
2963     setTitle: function(str) {
2964         this.titleEl.dom.innerHTML = str;
2965     },
2966     /**
2967      * Set the body of the Dialog
2968      * @param {String} str new Title
2969      */
2970     setBody: function(str) {
2971         this.bodyEl.dom.innerHTML = str;
2972     },
2973     /**
2974      * Set the body of the Dialog using the template
2975      * @param {Obj} data - apply this data to the template and replace the body contents.
2976      */
2977     applyBody: function(obj)
2978     {
2979         if (!this.tmpl) {
2980             Roo.log("Error - using apply Body without a template");
2981             //code
2982         }
2983         this.tmpl.overwrite(this.bodyEl, obj);
2984     }
2985
2986 });
2987
2988
2989 Roo.apply(Roo.bootstrap.Modal,  {
2990     /**
2991          * Button config that displays a single OK button
2992          * @type Object
2993          */
2994         OK :  [{
2995             name : 'ok',
2996             weight : 'primary',
2997             html : 'OK'
2998         }],
2999         /**
3000          * Button config that displays Yes and No buttons
3001          * @type Object
3002          */
3003         YESNO : [
3004             {
3005                 name  : 'no',
3006                 html : 'No'
3007             },
3008             {
3009                 name  :'yes',
3010                 weight : 'primary',
3011                 html : 'Yes'
3012             }
3013         ],
3014
3015         /**
3016          * Button config that displays OK and Cancel buttons
3017          * @type Object
3018          */
3019         OKCANCEL : [
3020             {
3021                name : 'cancel',
3022                 html : 'Cancel'
3023             },
3024             {
3025                 name : 'ok',
3026                 weight : 'primary',
3027                 html : 'OK'
3028             }
3029         ],
3030         /**
3031          * Button config that displays Yes, No and Cancel buttons
3032          * @type Object
3033          */
3034         YESNOCANCEL : [
3035             {
3036                 name : 'yes',
3037                 weight : 'primary',
3038                 html : 'Yes'
3039             },
3040             {
3041                 name : 'no',
3042                 html : 'No'
3043             },
3044             {
3045                 name : 'cancel',
3046                 html : 'Cancel'
3047             }
3048         ],
3049         
3050         zIndex : 10001
3051 });
3052 /*
3053  * - LGPL
3054  *
3055  * messagebox - can be used as a replace
3056  * 
3057  */
3058 /**
3059  * @class Roo.MessageBox
3060  * Utility class for generating different styles of message boxes.  The alias Roo.Msg can also be used.
3061  * Example usage:
3062  *<pre><code>
3063 // Basic alert:
3064 Roo.Msg.alert('Status', 'Changes saved successfully.');
3065
3066 // Prompt for user data:
3067 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3068     if (btn == 'ok'){
3069         // process text value...
3070     }
3071 });
3072
3073 // Show a dialog using config options:
3074 Roo.Msg.show({
3075    title:'Save Changes?',
3076    msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3077    buttons: Roo.Msg.YESNOCANCEL,
3078    fn: processResult,
3079    animEl: 'elId'
3080 });
3081 </code></pre>
3082  * @singleton
3083  */
3084 Roo.bootstrap.MessageBox = function(){
3085     var dlg, opt, mask, waitTimer;
3086     var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3087     var buttons, activeTextEl, bwidth;
3088
3089     
3090     // private
3091     var handleButton = function(button){
3092         dlg.hide();
3093         Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3094     };
3095
3096     // private
3097     var handleHide = function(){
3098         if(opt && opt.cls){
3099             dlg.el.removeClass(opt.cls);
3100         }
3101         //if(waitTimer){
3102         //    Roo.TaskMgr.stop(waitTimer);
3103         //    waitTimer = null;
3104         //}
3105     };
3106
3107     // private
3108     var updateButtons = function(b){
3109         var width = 0;
3110         if(!b){
3111             buttons["ok"].hide();
3112             buttons["cancel"].hide();
3113             buttons["yes"].hide();
3114             buttons["no"].hide();
3115             //dlg.footer.dom.style.display = 'none';
3116             return width;
3117         }
3118         dlg.footerEl.dom.style.display = '';
3119         for(var k in buttons){
3120             if(typeof buttons[k] != "function"){
3121                 if(b[k]){
3122                     buttons[k].show();
3123                     buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3124                     width += buttons[k].el.getWidth()+15;
3125                 }else{
3126                     buttons[k].hide();
3127                 }
3128             }
3129         }
3130         return width;
3131     };
3132
3133     // private
3134     var handleEsc = function(d, k, e){
3135         if(opt && opt.closable !== false){
3136             dlg.hide();
3137         }
3138         if(e){
3139             e.stopEvent();
3140         }
3141     };
3142
3143     return {
3144         /**
3145          * Returns a reference to the underlying {@link Roo.BasicDialog} element
3146          * @return {Roo.BasicDialog} The BasicDialog element
3147          */
3148         getDialog : function(){
3149            if(!dlg){
3150                 dlg = new Roo.bootstrap.Modal( {
3151                     //draggable: true,
3152                     //resizable:false,
3153                     //constraintoviewport:false,
3154                     //fixedcenter:true,
3155                     //collapsible : false,
3156                     //shim:true,
3157                     //modal: true,
3158                 //    width: 'auto',
3159                   //  height:100,
3160                     //buttonAlign:"center",
3161                     closeClick : function(){
3162                         if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3163                             handleButton("no");
3164                         }else{
3165                             handleButton("cancel");
3166                         }
3167                     }
3168                 });
3169                 dlg.render();
3170                 dlg.on("hide", handleHide);
3171                 mask = dlg.mask;
3172                 //dlg.addKeyListener(27, handleEsc);
3173                 buttons = {};
3174                 this.buttons = buttons;
3175                 var bt = this.buttonText;
3176                 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3177                 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3178                 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3179                 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3180                 //Roo.log(buttons);
3181                 bodyEl = dlg.bodyEl.createChild({
3182
3183                     html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3184                         '<textarea class="roo-mb-textarea"></textarea>' +
3185                         '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar">&#160;</div></div></div>'
3186                 });
3187                 msgEl = bodyEl.dom.firstChild;
3188                 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3189                 textboxEl.enableDisplayMode();
3190                 textboxEl.addKeyListener([10,13], function(){
3191                     if(dlg.isVisible() && opt && opt.buttons){
3192                         if(opt.buttons.ok){
3193                             handleButton("ok");
3194                         }else if(opt.buttons.yes){
3195                             handleButton("yes");
3196                         }
3197                     }
3198                 });
3199                 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3200                 textareaEl.enableDisplayMode();
3201                 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3202                 progressEl.enableDisplayMode();
3203                 
3204                 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3205                 var pf = progressEl.dom.firstChild;
3206                 if (pf) {
3207                     pp = Roo.get(pf.firstChild);
3208                     pp.setHeight(pf.offsetHeight);
3209                 }
3210                 
3211             }
3212             return dlg;
3213         },
3214
3215         /**
3216          * Updates the message box body text
3217          * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3218          * the XHTML-compliant non-breaking space character '&amp;#160;')
3219          * @return {Roo.MessageBox} This message box
3220          */
3221         updateText : function(text)
3222         {
3223             if(!dlg.isVisible() && !opt.width){
3224                 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3225                 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3226             }
3227             msgEl.innerHTML = text || '&#160;';
3228       
3229             var cw =  Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3230             //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3231             var w = Math.max(
3232                     Math.min(opt.width || cw , this.maxWidth), 
3233                     Math.max(opt.minWidth || this.minWidth, bwidth)
3234             );
3235             if(opt.prompt){
3236                 activeTextEl.setWidth(w);
3237             }
3238             if(dlg.isVisible()){
3239                 dlg.fixedcenter = false;
3240             }
3241             // to big, make it scroll. = But as usual stupid IE does not support
3242             // !important..
3243             
3244             if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3245                 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3246                 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3247             } else {
3248                 bodyEl.dom.style.height = '';
3249                 bodyEl.dom.style.overflowY = '';
3250             }
3251             if (cw > w) {
3252                 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3253             } else {
3254                 bodyEl.dom.style.overflowX = '';
3255             }
3256             
3257             dlg.setContentSize(w, bodyEl.getHeight());
3258             if(dlg.isVisible()){
3259                 dlg.fixedcenter = true;
3260             }
3261             return this;
3262         },
3263
3264         /**
3265          * Updates a progress-style message box's text and progress bar.  Only relevant on message boxes
3266          * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3267          * @param {Number} value Any number between 0 and 1 (e.g., .5)
3268          * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3269          * @return {Roo.MessageBox} This message box
3270          */
3271         updateProgress : function(value, text){
3272             if(text){
3273                 this.updateText(text);
3274             }
3275             
3276             if (pp) { // weird bug on my firefox - for some reason this is not defined
3277                 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3278                 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3279             }
3280             return this;
3281         },        
3282
3283         /**
3284          * Returns true if the message box is currently displayed
3285          * @return {Boolean} True if the message box is visible, else false
3286          */
3287         isVisible : function(){
3288             return dlg && dlg.isVisible();  
3289         },
3290
3291         /**
3292          * Hides the message box if it is displayed
3293          */
3294         hide : function(){
3295             if(this.isVisible()){
3296                 dlg.hide();
3297             }  
3298         },
3299
3300         /**
3301          * Displays a new message box, or reinitializes an existing message box, based on the config options
3302          * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3303          * The following config object properties are supported:
3304          * <pre>
3305 Property    Type             Description
3306 ----------  ---------------  ------------------------------------------------------------------------------------
3307 animEl            String/Element   An id or Element from which the message box should animate as it opens and
3308                                    closes (defaults to undefined)
3309 buttons           Object/Boolean   A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3310                                    cancel:'Bar'}), or false to not show any buttons (defaults to false)
3311 closable          Boolean          False to hide the top-right close button (defaults to true).  Note that
3312                                    progress and wait dialogs will ignore this property and always hide the
3313                                    close button as they can only be closed programmatically.
3314 cls               String           A custom CSS class to apply to the message box element
3315 defaultTextHeight Number           The default height in pixels of the message box's multiline textarea if
3316                                    displayed (defaults to 75)
3317 fn                Function         A callback function to execute after closing the dialog.  The arguments to the
3318                                    function will be btn (the name of the button that was clicked, if applicable,
3319                                    e.g. "ok"), and text (the value of the active text field, if applicable).
3320                                    Progress and wait dialogs will ignore this option since they do not respond to
3321                                    user actions and can only be closed programmatically, so any required function
3322                                    should be called by the same code after it closes the dialog.
3323 icon              String           A CSS class that provides a background image to be used as an icon for
3324                                    the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3325 maxWidth          Number           The maximum width in pixels of the message box (defaults to 600)
3326 minWidth          Number           The minimum width in pixels of the message box (defaults to 100)
3327 modal             Boolean          False to allow user interaction with the page while the message box is
3328                                    displayed (defaults to true)
3329 msg               String           A string that will replace the existing message box body text (defaults
3330                                    to the XHTML-compliant non-breaking space character '&#160;')
3331 multiline         Boolean          True to prompt the user to enter multi-line text (defaults to false)
3332 progress          Boolean          True to display a progress bar (defaults to false)
3333 progressText      String           The text to display inside the progress bar if progress = true (defaults to '')
3334 prompt            Boolean          True to prompt the user to enter single-line text (defaults to false)
3335 proxyDrag         Boolean          True to display a lightweight proxy while dragging (defaults to false)
3336 title             String           The title text
3337 value             String           The string value to set into the active textbox element if displayed
3338 wait              Boolean          True to display a progress bar (defaults to false)
3339 width             Number           The width of the dialog in pixels
3340 </pre>
3341          *
3342          * Example usage:
3343          * <pre><code>
3344 Roo.Msg.show({
3345    title: 'Address',
3346    msg: 'Please enter your address:',
3347    width: 300,
3348    buttons: Roo.MessageBox.OKCANCEL,
3349    multiline: true,
3350    fn: saveAddress,
3351    animEl: 'addAddressBtn'
3352 });
3353 </code></pre>
3354          * @param {Object} config Configuration options
3355          * @return {Roo.MessageBox} This message box
3356          */
3357         show : function(options)
3358         {
3359             
3360             // this causes nightmares if you show one dialog after another
3361             // especially on callbacks..
3362              
3363             if(this.isVisible()){
3364                 
3365                 this.hide();
3366                 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3367                 Roo.log("Old Dialog Message:" +  msgEl.innerHTML );
3368                 Roo.log("New Dialog Message:" +  options.msg )
3369                 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3370                 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3371                 
3372             }
3373             var d = this.getDialog();
3374             opt = options;
3375             d.setTitle(opt.title || "&#160;");
3376             d.closeEl.setDisplayed(opt.closable !== false);
3377             activeTextEl = textboxEl;
3378             opt.prompt = opt.prompt || (opt.multiline ? true : false);
3379             if(opt.prompt){
3380                 if(opt.multiline){
3381                     textboxEl.hide();
3382                     textareaEl.show();
3383                     textareaEl.setHeight(typeof opt.multiline == "number" ?
3384                         opt.multiline : this.defaultTextHeight);
3385                     activeTextEl = textareaEl;
3386                 }else{
3387                     textboxEl.show();
3388                     textareaEl.hide();
3389                 }
3390             }else{
3391                 textboxEl.hide();
3392                 textareaEl.hide();
3393             }
3394             progressEl.setDisplayed(opt.progress === true);
3395             this.updateProgress(0);
3396             activeTextEl.dom.value = opt.value || "";
3397             if(opt.prompt){
3398                 dlg.setDefaultButton(activeTextEl);
3399             }else{
3400                 var bs = opt.buttons;
3401                 var db = null;
3402                 if(bs && bs.ok){
3403                     db = buttons["ok"];
3404                 }else if(bs && bs.yes){
3405                     db = buttons["yes"];
3406                 }
3407                 dlg.setDefaultButton(db);
3408             }
3409             bwidth = updateButtons(opt.buttons);
3410             this.updateText(opt.msg);
3411             if(opt.cls){
3412                 d.el.addClass(opt.cls);
3413             }
3414             d.proxyDrag = opt.proxyDrag === true;
3415             d.modal = opt.modal !== false;
3416             d.mask = opt.modal !== false ? mask : false;
3417             if(!d.isVisible()){
3418                 // force it to the end of the z-index stack so it gets a cursor in FF
3419                 document.body.appendChild(dlg.el.dom);
3420                 d.animateTarget = null;
3421                 d.show(options.animEl);
3422             }
3423             return this;
3424         },
3425
3426         /**
3427          * Displays a message box with a progress bar.  This message box has no buttons and is not closeable by
3428          * the user.  You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3429          * and closing the message box when the process is complete.
3430          * @param {String} title The title bar text
3431          * @param {String} msg The message box body text
3432          * @return {Roo.MessageBox} This message box
3433          */
3434         progress : function(title, msg){
3435             this.show({
3436                 title : title,
3437                 msg : msg,
3438                 buttons: false,
3439                 progress:true,
3440                 closable:false,
3441                 minWidth: this.minProgressWidth,
3442                 modal : true
3443             });
3444             return this;
3445         },
3446
3447         /**
3448          * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3449          * If a callback function is passed it will be called after the user clicks the button, and the
3450          * id of the button that was clicked will be passed as the only parameter to the callback
3451          * (could also be the top-right close button).
3452          * @param {String} title The title bar text
3453          * @param {String} msg The message box body text
3454          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3455          * @param {Object} scope (optional) The scope of the callback function
3456          * @return {Roo.MessageBox} This message box
3457          */
3458         alert : function(title, msg, fn, scope)
3459         {
3460             this.show({
3461                 title : title,
3462                 msg : msg,
3463                 buttons: this.OK,
3464                 fn: fn,
3465                 closable : false,
3466                 scope : scope,
3467                 modal : true
3468             });
3469             return this;
3470         },
3471
3472         /**
3473          * Displays a message box with an infinitely auto-updating progress bar.  This can be used to block user
3474          * interaction while waiting for a long-running process to complete that does not have defined intervals.
3475          * You are responsible for closing the message box when the process is complete.
3476          * @param {String} msg The message box body text
3477          * @param {String} title (optional) The title bar text
3478          * @return {Roo.MessageBox} This message box
3479          */
3480         wait : function(msg, title){
3481             this.show({
3482                 title : title,
3483                 msg : msg,
3484                 buttons: false,
3485                 closable:false,
3486                 progress:true,
3487                 modal:true,
3488                 width:300,
3489                 wait:true
3490             });
3491             waitTimer = Roo.TaskMgr.start({
3492                 run: function(i){
3493                     Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3494                 },
3495                 interval: 1000
3496             });
3497             return this;
3498         },
3499
3500         /**
3501          * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3502          * If a callback function is passed it will be called after the user clicks either button, and the id of the
3503          * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3504          * @param {String} title The title bar text
3505          * @param {String} msg The message box body text
3506          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3507          * @param {Object} scope (optional) The scope of the callback function
3508          * @return {Roo.MessageBox} This message box
3509          */
3510         confirm : function(title, msg, fn, scope){
3511             this.show({
3512                 title : title,
3513                 msg : msg,
3514                 buttons: this.YESNO,
3515                 fn: fn,
3516                 scope : scope,
3517                 modal : true
3518             });
3519             return this;
3520         },
3521
3522         /**
3523          * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3524          * JavaScript's Window.prompt).  The prompt can be a single-line or multi-line textbox.  If a callback function
3525          * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3526          * (could also be the top-right close button) and the text that was entered will be passed as the two
3527          * parameters to the callback.
3528          * @param {String} title The title bar text
3529          * @param {String} msg The message box body text
3530          * @param {Function} fn (optional) The callback function invoked after the message box is closed
3531          * @param {Object} scope (optional) The scope of the callback function
3532          * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3533          * property, or the height in pixels to create the textbox (defaults to false / single-line)
3534          * @return {Roo.MessageBox} This message box
3535          */
3536         prompt : function(title, msg, fn, scope, multiline){
3537             this.show({
3538                 title : title,
3539                 msg : msg,
3540                 buttons: this.OKCANCEL,
3541                 fn: fn,
3542                 minWidth:250,
3543                 scope : scope,
3544                 prompt:true,
3545                 multiline: multiline,
3546                 modal : true
3547             });
3548             return this;
3549         },
3550
3551         /**
3552          * Button config that displays a single OK button
3553          * @type Object
3554          */
3555         OK : {ok:true},
3556         /**
3557          * Button config that displays Yes and No buttons
3558          * @type Object
3559          */
3560         YESNO : {yes:true, no:true},
3561         /**
3562          * Button config that displays OK and Cancel buttons
3563          * @type Object
3564          */
3565         OKCANCEL : {ok:true, cancel:true},
3566         /**
3567          * Button config that displays Yes, No and Cancel buttons
3568          * @type Object
3569          */
3570         YESNOCANCEL : {yes:true, no:true, cancel:true},
3571
3572         /**
3573          * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3574          * @type Number
3575          */
3576         defaultTextHeight : 75,
3577         /**
3578          * The maximum width in pixels of the message box (defaults to 600)
3579          * @type Number
3580          */
3581         maxWidth : 600,
3582         /**
3583          * The minimum width in pixels of the message box (defaults to 100)
3584          * @type Number
3585          */
3586         minWidth : 100,
3587         /**
3588          * The minimum width in pixels of the message box if it is a progress-style dialog.  This is useful
3589          * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3590          * @type Number
3591          */
3592         minProgressWidth : 250,
3593         /**
3594          * An object containing the default button text strings that can be overriden for localized language support.
3595          * Supported properties are: ok, cancel, yes and no.
3596          * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3597          * @type Object
3598          */
3599         buttonText : {
3600             ok : "OK",
3601             cancel : "Cancel",
3602             yes : "Yes",
3603             no : "No"
3604         }
3605     };
3606 }();
3607
3608 /**
3609  * Shorthand for {@link Roo.MessageBox}
3610  */
3611 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3612 Roo.Msg = Roo.Msg || Roo.MessageBox;
3613 /*
3614  * - LGPL
3615  *
3616  * navbar
3617  * 
3618  */
3619
3620 /**
3621  * @class Roo.bootstrap.Navbar
3622  * @extends Roo.bootstrap.Component
3623  * Bootstrap Navbar class
3624
3625  * @constructor
3626  * Create a new Navbar
3627  * @param {Object} config The config object
3628  */
3629
3630
3631 Roo.bootstrap.Navbar = function(config){
3632     Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3633     this.addEvents({
3634         // raw events
3635         /**
3636          * @event beforetoggle
3637          * Fire before toggle the menu
3638          * @param {Roo.EventObject} e
3639          */
3640         "beforetoggle" : true
3641     });
3642 };
3643
3644 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component,  {
3645     
3646     
3647    
3648     // private
3649     navItems : false,
3650     loadMask : false,
3651     
3652     
3653     getAutoCreate : function(){
3654         
3655         
3656         throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3657         
3658     },
3659     
3660     initEvents :function ()
3661     {
3662         //Roo.log(this.el.select('.navbar-toggle',true));
3663         this.el.select('.navbar-toggle',true).on('click', function() {
3664             if(this.fireEvent('beforetoggle', this) !== false){
3665                this.el.select('.navbar-collapse',true).toggleClass('in');                                 
3666             }
3667             
3668         }, this);
3669         
3670         var mark = {
3671             tag: "div",
3672             cls:"x-dlg-mask"
3673         };
3674         
3675         this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3676         
3677         var size = this.el.getSize();
3678         this.maskEl.setSize(size.width, size.height);
3679         this.maskEl.enableDisplayMode("block");
3680         this.maskEl.hide();
3681         
3682         if(this.loadMask){
3683             this.maskEl.show();
3684         }
3685     },
3686     
3687     
3688     getChildContainer : function()
3689     {
3690         if (this.el.select('.collapse').getCount()) {
3691             return this.el.select('.collapse',true).first();
3692         }
3693         
3694         return this.el;
3695     },
3696     
3697     mask : function()
3698     {
3699         this.maskEl.show();
3700     },
3701     
3702     unmask : function()
3703     {
3704         this.maskEl.hide();
3705     } 
3706     
3707     
3708     
3709     
3710 });
3711
3712
3713
3714  
3715
3716  /*
3717  * - LGPL
3718  *
3719  * navbar
3720  * 
3721  */
3722
3723 /**
3724  * @class Roo.bootstrap.NavSimplebar
3725  * @extends Roo.bootstrap.Navbar
3726  * Bootstrap Sidebar class
3727  *
3728  * @cfg {Boolean} inverse is inverted color
3729  * 
3730  * @cfg {String} type (nav | pills | tabs)
3731  * @cfg {Boolean} arrangement stacked | justified
3732  * @cfg {String} align (left | right) alignment
3733  * 
3734  * @cfg {Boolean} main (true|false) main nav bar? default false
3735  * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3736  * 
3737  * @cfg {String} tag (header|footer|nav|div) default is nav 
3738
3739  * 
3740  * 
3741  * 
3742  * @constructor
3743  * Create a new Sidebar
3744  * @param {Object} config The config object
3745  */
3746
3747
3748 Roo.bootstrap.NavSimplebar = function(config){
3749     Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3750 };
3751
3752 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar,  {
3753     
3754     inverse: false,
3755     
3756     type: false,
3757     arrangement: '',
3758     align : false,
3759     
3760     
3761     
3762     main : false,
3763     
3764     
3765     tag : false,
3766     
3767     
3768     getAutoCreate : function(){
3769         
3770         
3771         var cfg = {
3772             tag : this.tag || 'div',
3773             cls : 'navbar'
3774         };
3775           
3776         
3777         cfg.cn = [
3778             {
3779                 cls: 'nav',
3780                 tag : 'ul'
3781             }
3782         ];
3783         
3784          
3785         this.type = this.type || 'nav';
3786         if (['tabs','pills'].indexOf(this.type)!==-1) {
3787             cfg.cn[0].cls += ' nav-' + this.type
3788         
3789         
3790         } else {
3791             if (this.type!=='nav') {
3792                 Roo.log('nav type must be nav/tabs/pills')
3793             }
3794             cfg.cn[0].cls += ' navbar-nav'
3795         }
3796         
3797         
3798         
3799         
3800         if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3801             cfg.cn[0].cls += ' nav-' + this.arrangement;
3802         }
3803         
3804         
3805         if (this.align === 'right') {
3806             cfg.cn[0].cls += ' navbar-right';
3807         }
3808         
3809         if (this.inverse) {
3810             cfg.cls += ' navbar-inverse';
3811             
3812         }
3813         
3814         
3815         return cfg;
3816     
3817         
3818     }
3819     
3820     
3821     
3822 });
3823
3824
3825
3826  
3827
3828  
3829        /*
3830  * - LGPL
3831  *
3832  * navbar
3833  * 
3834  */
3835
3836 /**
3837  * @class Roo.bootstrap.NavHeaderbar
3838  * @extends Roo.bootstrap.NavSimplebar
3839  * Bootstrap Sidebar class
3840  *
3841  * @cfg {String} brand what is brand
3842  * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3843  * @cfg {String} brand_href href of the brand
3844  * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button   default true
3845  * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3846  * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3847  * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3848  * 
3849  * @constructor
3850  * Create a new Sidebar
3851  * @param {Object} config The config object
3852  */
3853
3854
3855 Roo.bootstrap.NavHeaderbar = function(config){
3856     Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3857       
3858 };
3859
3860 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar,  {
3861     
3862     position: '',
3863     brand: '',
3864     brand_href: false,
3865     srButton : true,
3866     autohide : false,
3867     desktopCenter : false,
3868    
3869     
3870     getAutoCreate : function(){
3871         
3872         var   cfg = {
3873             tag: this.nav || 'nav',
3874             cls: 'navbar',
3875             role: 'navigation',
3876             cn: []
3877         };
3878         
3879         var cn = cfg.cn;
3880         if (this.desktopCenter) {
3881             cn.push({cls : 'container', cn : []});
3882             cn = cn[0].cn;
3883         }
3884         
3885         if(this.srButton){
3886             cn.push({
3887                 tag: 'div',
3888                 cls: 'navbar-header',
3889                 cn: [
3890                     {
3891                         tag: 'button',
3892                         type: 'button',
3893                         cls: 'navbar-toggle',
3894                         'data-toggle': 'collapse',
3895                         cn: [
3896                             {
3897                                 tag: 'span',
3898                                 cls: 'sr-only',
3899                                 html: 'Toggle navigation'
3900                             },
3901                             {
3902                                 tag: 'span',
3903                                 cls: 'icon-bar'
3904                             },
3905                             {
3906                                 tag: 'span',
3907                                 cls: 'icon-bar'
3908                             },
3909                             {
3910                                 tag: 'span',
3911                                 cls: 'icon-bar'
3912                             }
3913                         ]
3914                     }
3915                 ]
3916             });
3917         }
3918         
3919         cn.push({
3920             tag: 'div',
3921             cls: 'collapse navbar-collapse',
3922             cn : []
3923         });
3924         
3925         cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3926         
3927         if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3928             cfg.cls += ' navbar-' + this.position;
3929             
3930             // tag can override this..
3931             
3932             cfg.tag = this.tag || (this.position  == 'fixed-bottom' ? 'footer' : 'header');
3933         }
3934         
3935         if (this.brand !== '') {
3936             cn[0].cn.push({
3937                 tag: 'a',
3938                 href: this.brand_href ? this.brand_href : '#',
3939                 cls: 'navbar-brand',
3940                 cn: [
3941                 this.brand
3942                 ]
3943             });
3944         }
3945         
3946         if(this.main){
3947             cfg.cls += ' main-nav';
3948         }
3949         
3950         
3951         return cfg;
3952
3953         
3954     },
3955     getHeaderChildContainer : function()
3956     {
3957         if (this.srButton && this.el.select('.navbar-header').getCount()) {
3958             return this.el.select('.navbar-header',true).first();
3959         }
3960         
3961         return this.getChildContainer();
3962     },
3963     
3964     
3965     initEvents : function()
3966     {
3967         Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3968         
3969         if (this.autohide) {
3970             
3971             var prevScroll = 0;
3972             var ft = this.el;
3973             
3974             Roo.get(document).on('scroll',function(e) {
3975                 var ns = Roo.get(document).getScroll().top;
3976                 var os = prevScroll;
3977                 prevScroll = ns;
3978                 
3979                 if(ns > os){
3980                     ft.removeClass('slideDown');
3981                     ft.addClass('slideUp');
3982                     return;
3983                 }
3984                 ft.removeClass('slideUp');
3985                 ft.addClass('slideDown');
3986                  
3987               
3988           },this);
3989         }
3990     }    
3991     
3992 });
3993
3994
3995
3996  
3997
3998  /*
3999  * - LGPL
4000  *
4001  * navbar
4002  * 
4003  */
4004
4005 /**
4006  * @class Roo.bootstrap.NavSidebar
4007  * @extends Roo.bootstrap.Navbar
4008  * Bootstrap Sidebar class
4009  * 
4010  * @constructor
4011  * Create a new Sidebar
4012  * @param {Object} config The config object
4013  */
4014
4015
4016 Roo.bootstrap.NavSidebar = function(config){
4017     Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4018 };
4019
4020 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar,  {
4021     
4022     sidebar : true, // used by Navbar Item and NavbarGroup at present...
4023     
4024     getAutoCreate : function(){
4025         
4026         
4027         return  {
4028             tag: 'div',
4029             cls: 'sidebar sidebar-nav'
4030         };
4031     
4032         
4033     }
4034     
4035     
4036     
4037 });
4038
4039
4040
4041  
4042
4043  /*
4044  * - LGPL
4045  *
4046  * nav group
4047  * 
4048  */
4049
4050 /**
4051  * @class Roo.bootstrap.NavGroup
4052  * @extends Roo.bootstrap.Component
4053  * Bootstrap NavGroup class
4054  * @cfg {String} align (left|right)
4055  * @cfg {Boolean} inverse
4056  * @cfg {String} type (nav|pills|tab) default nav
4057  * @cfg {String} navId - reference Id for navbar.
4058
4059  * 
4060  * @constructor
4061  * Create a new nav group
4062  * @param {Object} config The config object
4063  */
4064
4065 Roo.bootstrap.NavGroup = function(config){
4066     Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4067     this.navItems = [];
4068    
4069     Roo.bootstrap.NavGroup.register(this);
4070      this.addEvents({
4071         /**
4072              * @event changed
4073              * Fires when the active item changes
4074              * @param {Roo.bootstrap.NavGroup} this
4075              * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4076              * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item 
4077          */
4078         'changed': true
4079      });
4080     
4081 };
4082
4083 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component,  {
4084     
4085     align: '',
4086     inverse: false,
4087     form: false,
4088     type: 'nav',
4089     navId : '',
4090     // private
4091     
4092     navItems : false, 
4093     
4094     getAutoCreate : function()
4095     {
4096         var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4097         
4098         cfg = {
4099             tag : 'ul',
4100             cls: 'nav' 
4101         };
4102         
4103         if (['tabs','pills'].indexOf(this.type)!==-1) {
4104             cfg.cls += ' nav-' + this.type
4105         } else {
4106             if (this.type!=='nav') {
4107                 Roo.log('nav type must be nav/tabs/pills')
4108             }
4109             cfg.cls += ' navbar-nav'
4110         }
4111         
4112         if (this.parent() && this.parent().sidebar) {
4113             cfg = {
4114                 tag: 'ul',
4115                 cls: 'dashboard-menu sidebar-menu'
4116             };
4117             
4118             return cfg;
4119         }
4120         
4121         if (this.form === true) {
4122             cfg = {
4123                 tag: 'form',
4124                 cls: 'navbar-form'
4125             };
4126             
4127             if (this.align === 'right') {
4128                 cfg.cls += ' navbar-right';
4129             } else {
4130                 cfg.cls += ' navbar-left';
4131             }
4132         }
4133         
4134         if (this.align === 'right') {
4135             cfg.cls += ' navbar-right';
4136         }
4137         
4138         if (this.inverse) {
4139             cfg.cls += ' navbar-inverse';
4140             
4141         }
4142         
4143         
4144         return cfg;
4145     },
4146     /**
4147     * sets the active Navigation item
4148     * @param {Roo.bootstrap.NavItem} the new current navitem
4149     */
4150     setActiveItem : function(item)
4151     {
4152         var prev = false;
4153         Roo.each(this.navItems, function(v){
4154             if (v == item) {
4155                 return ;
4156             }
4157             if (v.isActive()) {
4158                 v.setActive(false, true);
4159                 prev = v;
4160                 
4161             }
4162             
4163         });
4164
4165         item.setActive(true, true);
4166         this.fireEvent('changed', this, item, prev);
4167         
4168         
4169     },
4170     /**
4171     * gets the active Navigation item
4172     * @return {Roo.bootstrap.NavItem} the current navitem
4173     */
4174     getActive : function()
4175     {
4176         
4177         var prev = false;
4178         Roo.each(this.navItems, function(v){
4179             
4180             if (v.isActive()) {
4181                 prev = v;
4182                 
4183             }
4184             
4185         });
4186         return prev;
4187     },
4188     
4189     indexOfNav : function()
4190     {
4191         
4192         var prev = false;
4193         Roo.each(this.navItems, function(v,i){
4194             
4195             if (v.isActive()) {
4196                 prev = i;
4197                 
4198             }
4199             
4200         });
4201         return prev;
4202     },
4203     /**
4204     * adds a Navigation item
4205     * @param {Roo.bootstrap.NavItem} the navitem to add
4206     */
4207     addItem : function(cfg)
4208     {
4209         var cn = new Roo.bootstrap.NavItem(cfg);
4210         this.register(cn);
4211         cn.parentId = this.id;
4212         cn.onRender(this.el, null);
4213         return cn;
4214     },
4215     /**
4216     * register a Navigation item
4217     * @param {Roo.bootstrap.NavItem} the navitem to add
4218     */
4219     register : function(item)
4220     {
4221         this.navItems.push( item);
4222         item.navId = this.navId;
4223     
4224     },
4225     
4226     /**
4227     * clear all the Navigation item
4228     */
4229    
4230     clearAll : function()
4231     {
4232         this.navItems = [];
4233         this.el.dom.innerHTML = '';
4234     },
4235     
4236     getNavItem: function(tabId)
4237     {
4238         var ret = false;
4239         Roo.each(this.navItems, function(e) {
4240             if (e.tabId == tabId) {
4241                ret =  e;
4242                return false;
4243             }
4244             return true;
4245             
4246         });
4247         return ret;
4248     },
4249     
4250     setActiveNext : function()
4251     {
4252         var i = this.indexOfNav(this.getActive());
4253         if (i > this.navItems.length) {
4254             return;
4255         }
4256         this.setActiveItem(this.navItems[i+1]);
4257     },
4258     setActivePrev : function()
4259     {
4260         var i = this.indexOfNav(this.getActive());
4261         if (i  < 1) {
4262             return;
4263         }
4264         this.setActiveItem(this.navItems[i-1]);
4265     },
4266     clearWasActive : function(except) {
4267         Roo.each(this.navItems, function(e) {
4268             if (e.tabId != except.tabId && e.was_active) {
4269                e.was_active = false;
4270                return false;
4271             }
4272             return true;
4273             
4274         });
4275     },
4276     getWasActive : function ()
4277     {
4278         var r = false;
4279         Roo.each(this.navItems, function(e) {
4280             if (e.was_active) {
4281                r = e;
4282                return false;
4283             }
4284             return true;
4285             
4286         });
4287         return r;
4288     }
4289     
4290     
4291 });
4292
4293  
4294 Roo.apply(Roo.bootstrap.NavGroup, {
4295     
4296     groups: {},
4297      /**
4298     * register a Navigation Group
4299     * @param {Roo.bootstrap.NavGroup} the navgroup to add
4300     */
4301     register : function(navgrp)
4302     {
4303         this.groups[navgrp.navId] = navgrp;
4304         
4305     },
4306     /**
4307     * fetch a Navigation Group based on the navigation ID
4308     * @param {string} the navgroup to add
4309     * @returns {Roo.bootstrap.NavGroup} the navgroup 
4310     */
4311     get: function(navId) {
4312         if (typeof(this.groups[navId]) == 'undefined') {
4313             return false;
4314             //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4315         }
4316         return this.groups[navId] ;
4317     }
4318     
4319     
4320     
4321 });
4322
4323  /*
4324  * - LGPL
4325  *
4326  * row
4327  * 
4328  */
4329
4330 /**
4331  * @class Roo.bootstrap.NavItem
4332  * @extends Roo.bootstrap.Component
4333  * Bootstrap Navbar.NavItem class
4334  * @cfg {String} href  link to
4335  * @cfg {String} html content of button
4336  * @cfg {String} badge text inside badge
4337  * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4338  * @cfg {String} glyphicon name of glyphicon
4339  * @cfg {String} icon name of font awesome icon
4340  * @cfg {Boolean} active Is item active
4341  * @cfg {Boolean} disabled Is item disabled
4342  
4343  * @cfg {Boolean} preventDefault (true | false) default false
4344  * @cfg {String} tabId the tab that this item activates.
4345  * @cfg {String} tagtype (a|span) render as a href or span?
4346  * @cfg {Boolean} animateRef (true|false) link to element default false  
4347   
4348  * @constructor
4349  * Create a new Navbar Item
4350  * @param {Object} config The config object
4351  */
4352 Roo.bootstrap.NavItem = function(config){
4353     Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4354     this.addEvents({
4355         // raw events
4356         /**
4357          * @event click
4358          * The raw click event for the entire grid.
4359          * @param {Roo.EventObject} e
4360          */
4361         "click" : true,
4362          /**
4363             * @event changed
4364             * Fires when the active item active state changes
4365             * @param {Roo.bootstrap.NavItem} this
4366             * @param {boolean} state the new state
4367              
4368          */
4369         'changed': true,
4370         /**
4371             * @event scrollto
4372             * Fires when scroll to element
4373             * @param {Roo.bootstrap.NavItem} this
4374             * @param {Object} options
4375             * @param {Roo.EventObject} e
4376              
4377          */
4378         'scrollto': true
4379     });
4380    
4381 };
4382
4383 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component,  {
4384     
4385     href: false,
4386     html: '',
4387     badge: '',
4388     icon: false,
4389     glyphicon: false,
4390     active: false,
4391     preventDefault : false,
4392     tabId : false,
4393     tagtype : 'a',
4394     disabled : false,
4395     animateRef : false,
4396     was_active : false,
4397     
4398     getAutoCreate : function(){
4399          
4400         var cfg = {
4401             tag: 'li',
4402             cls: 'nav-item'
4403             
4404         };
4405         
4406         if (this.active) {
4407             cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4408         }
4409         if (this.disabled) {
4410             cfg.cls += ' disabled';
4411         }
4412         
4413         if (this.href || this.html || this.glyphicon || this.icon) {
4414             cfg.cn = [
4415                 {
4416                     tag: this.tagtype,
4417                     href : this.href || "#",
4418                     html: this.html || ''
4419                 }
4420             ];
4421             
4422             if (this.icon) {
4423                 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4424             }
4425
4426             if(this.glyphicon) {
4427                 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> '  + cfg.cn[0].html;
4428             }
4429             
4430             if (this.menu) {
4431                 
4432                 cfg.cn[0].html += " <span class='caret'></span>";
4433              
4434             }
4435             
4436             if (this.badge !== '') {
4437                  
4438                 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4439             }
4440         }
4441         
4442         
4443         
4444         return cfg;
4445     },
4446     initEvents: function() 
4447     {
4448         if (typeof (this.menu) != 'undefined') {
4449             this.menu.parentType = this.xtype;
4450             this.menu.triggerEl = this.el;
4451             this.menu = this.addxtype(Roo.apply({}, this.menu));
4452         }
4453         
4454         this.el.select('a',true).on('click', this.onClick, this);
4455         
4456         if(this.tagtype == 'span'){
4457             this.el.select('span',true).on('click', this.onClick, this);
4458         }
4459        
4460         // at this point parent should be available..
4461         this.parent().register(this);
4462     },
4463     
4464     onClick : function(e)
4465     {
4466         if (e.getTarget('.dropdown-menu-item')) {
4467             // did you click on a menu itemm.... - then don't trigger onclick..
4468             return;
4469         }
4470         
4471         if(
4472                 this.preventDefault || 
4473                 this.href == '#' 
4474         ){
4475             Roo.log("NavItem - prevent Default?");
4476             e.preventDefault();
4477         }
4478         
4479         if (this.disabled) {
4480             return;
4481         }
4482         
4483         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4484         if (tg && tg.transition) {
4485             Roo.log("waiting for the transitionend");
4486             return;
4487         }
4488         
4489         
4490         
4491         //Roo.log("fire event clicked");
4492         if(this.fireEvent('click', this, e) === false){
4493             return;
4494         };
4495         
4496         if(this.tagtype == 'span'){
4497             return;
4498         }
4499         
4500         //Roo.log(this.href);
4501         var ael = this.el.select('a',true).first();
4502         //Roo.log(ael);
4503         
4504         if(ael && this.animateRef && this.href.indexOf('#') > -1){
4505             //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4506             if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4507                 return; // ignore... - it's a 'hash' to another page.
4508             }
4509             Roo.log("NavItem - prevent Default?");
4510             e.preventDefault();
4511             this.scrollToElement(e);
4512         }
4513         
4514         
4515         var p =  this.parent();
4516    
4517         if (['tabs','pills'].indexOf(p.type)!==-1) {
4518             if (typeof(p.setActiveItem) !== 'undefined') {
4519                 p.setActiveItem(this);
4520             }
4521         }
4522         
4523         // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4524         if (p.parentType == 'NavHeaderbar' && !this.menu) {
4525             // remove the collapsed menu expand...
4526             p.parent().el.select('.navbar-collapse',true).removeClass('in');  
4527         }
4528     },
4529     
4530     isActive: function () {
4531         return this.active
4532     },
4533     setActive : function(state, fire, is_was_active)
4534     {
4535         if (this.active && !state && this.navId) {
4536             this.was_active = true;
4537             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4538             if (nv) {
4539                 nv.clearWasActive(this);
4540             }
4541             
4542         }
4543         this.active = state;
4544         
4545         if (!state ) {
4546             this.el.removeClass('active');
4547         } else if (!this.el.hasClass('active')) {
4548             this.el.addClass('active');
4549         }
4550         if (fire) {
4551             this.fireEvent('changed', this, state);
4552         }
4553         
4554         // show a panel if it's registered and related..
4555         
4556         if (!this.navId || !this.tabId || !state || is_was_active) {
4557             return;
4558         }
4559         
4560         var tg = Roo.bootstrap.TabGroup.get(this.navId);
4561         if (!tg) {
4562             return;
4563         }
4564         var pan = tg.getPanelByName(this.tabId);
4565         if (!pan) {
4566             return;
4567         }
4568         // if we can not flip to new panel - go back to old nav highlight..
4569         if (false == tg.showPanel(pan)) {
4570             var nv = Roo.bootstrap.NavGroup.get(this.navId);
4571             if (nv) {
4572                 var onav = nv.getWasActive();
4573                 if (onav) {
4574                     onav.setActive(true, false, true);
4575                 }
4576             }
4577             
4578         }
4579         
4580         
4581         
4582     },
4583      // this should not be here...
4584     setDisabled : function(state)
4585     {
4586         this.disabled = state;
4587         if (!state ) {
4588             this.el.removeClass('disabled');
4589         } else if (!this.el.hasClass('disabled')) {
4590             this.el.addClass('disabled');
4591         }
4592         
4593     },
4594     
4595     /**
4596      * Fetch the element to display the tooltip on.
4597      * @return {Roo.Element} defaults to this.el
4598      */
4599     tooltipEl : function()
4600     {
4601         return this.el.select('' + this.tagtype + '', true).first();
4602     },
4603     
4604     scrollToElement : function(e)
4605     {
4606         var c = document.body;
4607         
4608         /*
4609          * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4610          */
4611         if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4612             c = document.documentElement;
4613         }
4614         
4615         var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4616         
4617         if(!target){
4618             return;
4619         }
4620
4621         var o = target.calcOffsetsTo(c);
4622         
4623         var options = {
4624             target : target,
4625             value : o[1]
4626         };
4627         
4628         this.fireEvent('scrollto', this, options, e);
4629         
4630         Roo.get(c).scrollTo('top', options.value, true);
4631         
4632         return;
4633     }
4634 });
4635  
4636
4637  /*
4638  * - LGPL
4639  *
4640  * sidebar item
4641  *
4642  *  li
4643  *    <span> icon </span>
4644  *    <span> text </span>
4645  *    <span>badge </span>
4646  */
4647
4648 /**
4649  * @class Roo.bootstrap.NavSidebarItem
4650  * @extends Roo.bootstrap.NavItem
4651  * Bootstrap Navbar.NavSidebarItem class
4652  * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4653  * {Boolean} open is the menu open
4654  * {Boolean} buttonView use button as the tigger el rather that a (default false)
4655  * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4656  * {String} buttonSize (sm|md|lg)the extra classes for the button
4657  * {Boolean} showArrow show arrow next to the text (default true)
4658  * @constructor
4659  * Create a new Navbar Button
4660  * @param {Object} config The config object
4661  */
4662 Roo.bootstrap.NavSidebarItem = function(config){
4663     Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4664     this.addEvents({
4665         // raw events
4666         /**
4667          * @event click
4668          * The raw click event for the entire grid.
4669          * @param {Roo.EventObject} e
4670          */
4671         "click" : true,
4672          /**
4673             * @event changed
4674             * Fires when the active item active state changes
4675             * @param {Roo.bootstrap.NavSidebarItem} this
4676             * @param {boolean} state the new state
4677              
4678          */
4679         'changed': true
4680     });
4681    
4682 };
4683
4684 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem,  {
4685     
4686     badgeWeight : 'default',
4687     
4688     open: false,
4689     
4690     buttonView : false,
4691     
4692     buttonWeight : 'default',
4693     
4694     buttonSize : 'md',
4695     
4696     showArrow : true,
4697     
4698     getAutoCreate : function(){
4699         
4700         
4701         var a = {
4702                 tag: 'a',
4703                 href : this.href || '#',
4704                 cls: '',
4705                 html : '',
4706                 cn : []
4707         };
4708         
4709         if(this.buttonView){
4710             a = {
4711                 tag: 'button',
4712                 href : this.href || '#',
4713                 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4714                 html : this.html,
4715                 cn : []
4716             };
4717         }
4718         
4719         var cfg = {
4720             tag: 'li',
4721             cls: '',
4722             cn: [ a ]
4723         };
4724         
4725         if (this.active) {
4726             cfg.cls += ' active';
4727         }
4728         
4729         if (this.disabled) {
4730             cfg.cls += ' disabled';
4731         }
4732         if (this.open) {
4733             cfg.cls += ' open x-open';
4734         }
4735         // left icon..
4736         if (this.glyphicon || this.icon) {
4737             var c = this.glyphicon  ? ('glyphicon glyphicon-'+this.glyphicon)  : this.icon;
4738             a.cn.push({ tag : 'i', cls : c }) ;
4739         }
4740         
4741         if(!this.buttonView){
4742             var span = {
4743                 tag: 'span',
4744                 html : this.html || ''
4745             };
4746
4747             a.cn.push(span);
4748             
4749         }
4750         
4751         if (this.badge !== '') {
4752             a.cn.push({ tag: 'span',  cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge }); 
4753         }
4754         
4755         if (this.menu) {
4756             
4757             if(this.showArrow){
4758                 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4759             }
4760             
4761             a.cls += ' dropdown-toggle treeview' ;
4762         }
4763         
4764         return cfg;
4765     },
4766     
4767     initEvents : function()
4768     { 
4769         if (typeof (this.menu) != 'undefined') {
4770             this.menu.parentType = this.xtype;
4771             this.menu.triggerEl = this.el;
4772             this.menu = this.addxtype(Roo.apply({}, this.menu));
4773         }
4774         
4775         this.el.on('click', this.onClick, this);
4776         
4777         if(this.badge !== ''){
4778             this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4779         }
4780         
4781     },
4782     
4783     onClick : function(e)
4784     {
4785         if(this.disabled){
4786             e.preventDefault();
4787             return;
4788         }
4789         
4790         if(this.preventDefault){
4791             e.preventDefault();
4792         }
4793         
4794         this.fireEvent('click', this);
4795     },
4796     
4797     disable : function()
4798     {
4799         this.setDisabled(true);
4800     },
4801     
4802     enable : function()
4803     {
4804         this.setDisabled(false);
4805     },
4806     
4807     setDisabled : function(state)
4808     {
4809         if(this.disabled == state){
4810             return;
4811         }
4812         
4813         this.disabled = state;
4814         
4815         if (state) {
4816             this.el.addClass('disabled');
4817             return;
4818         }
4819         
4820         this.el.removeClass('disabled');
4821         
4822         return;
4823     },
4824     
4825     setActive : function(state)
4826     {
4827         if(this.active == state){
4828             return;
4829         }
4830         
4831         this.active = state;
4832         
4833         if (state) {
4834             this.el.addClass('active');
4835             return;
4836         }
4837         
4838         this.el.removeClass('active');
4839         
4840         return;
4841     },
4842     
4843     isActive: function () 
4844     {
4845         return this.active;
4846     },
4847     
4848     setBadge : function(str)
4849     {
4850         if(!this.badgeEl){
4851             return;
4852         }
4853         
4854         this.badgeEl.dom.innerHTML = str;
4855     }
4856     
4857    
4858      
4859  
4860 });
4861  
4862
4863  /*
4864  * - LGPL
4865  *
4866  * row
4867  * 
4868  */
4869
4870 /**
4871  * @class Roo.bootstrap.Row
4872  * @extends Roo.bootstrap.Component
4873  * Bootstrap Row class (contains columns...)
4874  * 
4875  * @constructor
4876  * Create a new Row
4877  * @param {Object} config The config object
4878  */
4879
4880 Roo.bootstrap.Row = function(config){
4881     Roo.bootstrap.Row.superclass.constructor.call(this, config);
4882 };
4883
4884 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component,  {
4885     
4886     getAutoCreate : function(){
4887        return {
4888             cls: 'row clearfix'
4889        };
4890     }
4891     
4892     
4893 });
4894
4895  
4896
4897  /*
4898  * - LGPL
4899  *
4900  * element
4901  * 
4902  */
4903
4904 /**
4905  * @class Roo.bootstrap.Element
4906  * @extends Roo.bootstrap.Component
4907  * Bootstrap Element class
4908  * @cfg {String} html contents of the element
4909  * @cfg {String} tag tag of the element
4910  * @cfg {String} cls class of the element
4911  * @cfg {Boolean} preventDefault (true|false) default false
4912  * @cfg {Boolean} clickable (true|false) default false
4913  * 
4914  * @constructor
4915  * Create a new Element
4916  * @param {Object} config The config object
4917  */
4918
4919 Roo.bootstrap.Element = function(config){
4920     Roo.bootstrap.Element.superclass.constructor.call(this, config);
4921     
4922     this.addEvents({
4923         // raw events
4924         /**
4925          * @event click
4926          * When a element is chick
4927          * @param {Roo.bootstrap.Element} this
4928          * @param {Roo.EventObject} e
4929          */
4930         "click" : true
4931     });
4932 };
4933
4934 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component,  {
4935     
4936     tag: 'div',
4937     cls: '',
4938     html: '',
4939     preventDefault: false, 
4940     clickable: false,
4941     
4942     getAutoCreate : function(){
4943         
4944         var cfg = {
4945             tag: this.tag,
4946             // cls: this.cls, double assign in parent class Component.js :: onRender
4947             html: this.html
4948         };
4949         
4950         return cfg;
4951     },
4952     
4953     initEvents: function() 
4954     {
4955         Roo.bootstrap.Element.superclass.initEvents.call(this);
4956         
4957         if(this.clickable){
4958             this.el.on('click', this.onClick, this);
4959         }
4960         
4961     },
4962     
4963     onClick : function(e)
4964     {
4965         if(this.preventDefault){
4966             e.preventDefault();
4967         }
4968         
4969         this.fireEvent('click', this, e);
4970     },
4971     
4972     getValue : function()
4973     {
4974         return this.el.dom.innerHTML;
4975     },
4976     
4977     setValue : function(value)
4978     {
4979         this.el.dom.innerHTML = value;
4980     }
4981    
4982 });
4983
4984  
4985
4986  /*
4987  * - LGPL
4988  *
4989  * pagination
4990  * 
4991  */
4992
4993 /**
4994  * @class Roo.bootstrap.Pagination
4995  * @extends Roo.bootstrap.Component
4996  * Bootstrap Pagination class
4997  * @cfg {String} size xs | sm | md | lg
4998  * @cfg {Boolean} inverse false | true
4999  * 
5000  * @constructor
5001  * Create a new Pagination
5002  * @param {Object} config The config object
5003  */
5004
5005 Roo.bootstrap.Pagination = function(config){
5006     Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5007 };
5008
5009 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component,  {
5010     
5011     cls: false,
5012     size: false,
5013     inverse: false,
5014     
5015     getAutoCreate : function(){
5016         var cfg = {
5017             tag: 'ul',
5018                 cls: 'pagination'
5019         };
5020         if (this.inverse) {
5021             cfg.cls += ' inverse';
5022         }
5023         if (this.html) {
5024             cfg.html=this.html;
5025         }
5026         if (this.cls) {
5027             cfg.cls += " " + this.cls;
5028         }
5029         return cfg;
5030     }
5031    
5032 });
5033
5034  
5035
5036  /*
5037  * - LGPL
5038  *
5039  * Pagination item
5040  * 
5041  */
5042
5043
5044 /**
5045  * @class Roo.bootstrap.PaginationItem
5046  * @extends Roo.bootstrap.Component
5047  * Bootstrap PaginationItem class
5048  * @cfg {String} html text
5049  * @cfg {String} href the link
5050  * @cfg {Boolean} preventDefault (true | false) default true
5051  * @cfg {Boolean} active (true | false) default false
5052  * @cfg {Boolean} disabled default false
5053  * 
5054  * 
5055  * @constructor
5056  * Create a new PaginationItem
5057  * @param {Object} config The config object
5058  */
5059
5060
5061 Roo.bootstrap.PaginationItem = function(config){
5062     Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5063     this.addEvents({
5064         // raw events
5065         /**
5066          * @event click
5067          * The raw click event for the entire grid.
5068          * @param {Roo.EventObject} e
5069          */
5070         "click" : true
5071     });
5072 };
5073
5074 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component,  {
5075     
5076     href : false,
5077     html : false,
5078     preventDefault: true,
5079     active : false,
5080     cls : false,
5081     disabled: false,
5082     
5083     getAutoCreate : function(){
5084         var cfg= {
5085             tag: 'li',
5086             cn: [
5087                 {
5088                     tag : 'a',
5089                     href : this.href ? this.href : '#',
5090                     html : this.html ? this.html : ''
5091                 }
5092             ]
5093         };
5094         
5095         if(this.cls){
5096             cfg.cls = this.cls;
5097         }
5098         
5099         if(this.disabled){
5100             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5101         }
5102         
5103         if(this.active){
5104             cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5105         }
5106         
5107         return cfg;
5108     },
5109     
5110     initEvents: function() {
5111         
5112         this.el.on('click', this.onClick, this);
5113         
5114     },
5115     onClick : function(e)
5116     {
5117         Roo.log('PaginationItem on click ');
5118         if(this.preventDefault){
5119             e.preventDefault();
5120         }
5121         
5122         if(this.disabled){
5123             return;
5124         }
5125         
5126         this.fireEvent('click', this, e);
5127     }
5128    
5129 });
5130
5131  
5132
5133  /*
5134  * - LGPL
5135  *
5136  * slider
5137  * 
5138  */
5139
5140
5141 /**
5142  * @class Roo.bootstrap.Slider
5143  * @extends Roo.bootstrap.Component
5144  * Bootstrap Slider class
5145  *    
5146  * @constructor
5147  * Create a new Slider
5148  * @param {Object} config The config object
5149  */
5150
5151 Roo.bootstrap.Slider = function(config){
5152     Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5153 };
5154
5155 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component,  {
5156     
5157     getAutoCreate : function(){
5158         
5159         var cfg = {
5160             tag: 'div',
5161             cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5162             cn: [
5163                 {
5164                     tag: 'a',
5165                     cls: 'ui-slider-handle ui-state-default ui-corner-all'
5166                 }
5167             ]
5168         };
5169         
5170         return cfg;
5171     }
5172    
5173 });
5174
5175  /*
5176  * Based on:
5177  * Ext JS Library 1.1.1
5178  * Copyright(c) 2006-2007, Ext JS, LLC.
5179  *
5180  * Originally Released Under LGPL - original licence link has changed is not relivant.
5181  *
5182  * Fork - LGPL
5183  * <script type="text/javascript">
5184  */
5185  
5186
5187 /**
5188  * @class Roo.grid.ColumnModel
5189  * @extends Roo.util.Observable
5190  * This is the default implementation of a ColumnModel used by the Grid. It defines
5191  * the columns in the grid.
5192  * <br>Usage:<br>
5193  <pre><code>
5194  var colModel = new Roo.grid.ColumnModel([
5195         {header: "Ticker", width: 60, sortable: true, locked: true},
5196         {header: "Company Name", width: 150, sortable: true},
5197         {header: "Market Cap.", width: 100, sortable: true},
5198         {header: "$ Sales", width: 100, sortable: true, renderer: money},
5199         {header: "Employees", width: 100, sortable: true, resizable: false}
5200  ]);
5201  </code></pre>
5202  * <p>
5203  
5204  * The config options listed for this class are options which may appear in each
5205  * individual column definition.
5206  * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5207  * @constructor
5208  * @param {Object} config An Array of column config objects. See this class's
5209  * config objects for details.
5210 */
5211 Roo.grid.ColumnModel = function(config){
5212         /**
5213      * The config passed into the constructor
5214      */
5215     this.config = config;
5216     this.lookup = {};
5217
5218     // if no id, create one
5219     // if the column does not have a dataIndex mapping,
5220     // map it to the order it is in the config
5221     for(var i = 0, len = config.length; i < len; i++){
5222         var c = config[i];
5223         if(typeof c.dataIndex == "undefined"){
5224             c.dataIndex = i;
5225         }
5226         if(typeof c.renderer == "string"){
5227             c.renderer = Roo.util.Format[c.renderer];
5228         }
5229         if(typeof c.id == "undefined"){
5230             c.id = Roo.id();
5231         }
5232         if(c.editor && c.editor.xtype){
5233             c.editor  = Roo.factory(c.editor, Roo.grid);
5234         }
5235         if(c.editor && c.editor.isFormField){
5236             c.editor = new Roo.grid.GridEditor(c.editor);
5237         }
5238         this.lookup[c.id] = c;
5239     }
5240
5241     /**
5242      * The width of columns which have no width specified (defaults to 100)
5243      * @type Number
5244      */
5245     this.defaultWidth = 100;
5246
5247     /**
5248      * Default sortable of columns which have no sortable specified (defaults to false)
5249      * @type Boolean
5250      */
5251     this.defaultSortable = false;
5252
5253     this.addEvents({
5254         /**
5255              * @event widthchange
5256              * Fires when the width of a column changes.
5257              * @param {ColumnModel} this
5258              * @param {Number} columnIndex The column index
5259              * @param {Number} newWidth The new width
5260              */
5261             "widthchange": true,
5262         /**
5263              * @event headerchange
5264              * Fires when the text of a header changes.
5265              * @param {ColumnModel} this
5266              * @param {Number} columnIndex The column index
5267              * @param {Number} newText The new header text
5268              */
5269             "headerchange": true,
5270         /**
5271              * @event hiddenchange
5272              * Fires when a column is hidden or "unhidden".
5273              * @param {ColumnModel} this
5274              * @param {Number} columnIndex The column index
5275              * @param {Boolean} hidden true if hidden, false otherwise
5276              */
5277             "hiddenchange": true,
5278             /**
5279          * @event columnmoved
5280          * Fires when a column is moved.
5281          * @param {ColumnModel} this
5282          * @param {Number} oldIndex
5283          * @param {Number} newIndex
5284          */
5285         "columnmoved" : true,
5286         /**
5287          * @event columlockchange
5288          * Fires when a column's locked state is changed
5289          * @param {ColumnModel} this
5290          * @param {Number} colIndex
5291          * @param {Boolean} locked true if locked
5292          */
5293         "columnlockchange" : true
5294     });
5295     Roo.grid.ColumnModel.superclass.constructor.call(this);
5296 };
5297 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5298     /**
5299      * @cfg {String} header The header text to display in the Grid view.
5300      */
5301     /**
5302      * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5303      * {@link Roo.data.Record} definition from which to draw the column's value. If not
5304      * specified, the column's index is used as an index into the Record's data Array.
5305      */
5306     /**
5307      * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5308      * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5309      */
5310     /**
5311      * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5312      * Defaults to the value of the {@link #defaultSortable} property.
5313      * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5314      */
5315     /**
5316      * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid.  Defaults to false.
5317      */
5318     /**
5319      * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed.  Defaults to false.
5320      */
5321     /**
5322      * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5323      */
5324     /**
5325      * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5326      */
5327     /**
5328      * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5329      * given the cell's data value. See {@link #setRenderer}. If not specified, the
5330      * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5331      * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5332      */
5333        /**
5334      * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor 
5335      */
5336     /**
5337      * @cfg {String} align (Optional) Set the CSS text-align property of the column.  Defaults to undefined.
5338      */
5339     /**
5340      * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc).  Defaults to undefined.
5341      */
5342     /**
5343      * @cfg {String} cursor (Optional)
5344      */
5345     /**
5346      * @cfg {String} tooltip (Optional)
5347      */
5348     /**
5349      * @cfg {Number} xs (Optional)
5350      */
5351     /**
5352      * @cfg {Number} sm (Optional)
5353      */
5354     /**
5355      * @cfg {Number} md (Optional)
5356      */
5357     /**
5358      * @cfg {Number} lg (Optional)
5359      */
5360     /**
5361      * Returns the id of the column at the specified index.
5362      * @param {Number} index The column index
5363      * @return {String} the id
5364      */
5365     getColumnId : function(index){
5366         return this.config[index].id;
5367     },
5368
5369     /**
5370      * Returns the column for a specified id.
5371      * @param {String} id The column id
5372      * @return {Object} the column
5373      */
5374     getColumnById : function(id){
5375         return this.lookup[id];
5376     },
5377
5378     
5379     /**
5380      * Returns the column for a specified dataIndex.
5381      * @param {String} dataIndex The column dataIndex
5382      * @return {Object|Boolean} the column or false if not found
5383      */
5384     getColumnByDataIndex: function(dataIndex){
5385         var index = this.findColumnIndex(dataIndex);
5386         return index > -1 ? this.config[index] : false;
5387     },
5388     
5389     /**
5390      * Returns the index for a specified column id.
5391      * @param {String} id The column id
5392      * @return {Number} the index, or -1 if not found
5393      */
5394     getIndexById : function(id){
5395         for(var i = 0, len = this.config.length; i < len; i++){
5396             if(this.config[i].id == id){
5397                 return i;
5398             }
5399         }
5400         return -1;
5401     },
5402     
5403     /**
5404      * Returns the index for a specified column dataIndex.
5405      * @param {String} dataIndex The column dataIndex
5406      * @return {Number} the index, or -1 if not found
5407      */
5408     
5409     findColumnIndex : function(dataIndex){
5410         for(var i = 0, len = this.config.length; i < len; i++){
5411             if(this.config[i].dataIndex == dataIndex){
5412                 return i;
5413             }
5414         }
5415         return -1;
5416     },
5417     
5418     
5419     moveColumn : function(oldIndex, newIndex){
5420         var c = this.config[oldIndex];
5421         this.config.splice(oldIndex, 1);
5422         this.config.splice(newIndex, 0, c);
5423         this.dataMap = null;
5424         this.fireEvent("columnmoved", this, oldIndex, newIndex);
5425     },
5426
5427     isLocked : function(colIndex){
5428         return this.config[colIndex].locked === true;
5429     },
5430
5431     setLocked : function(colIndex, value, suppressEvent){
5432         if(this.isLocked(colIndex) == value){
5433             return;
5434         }
5435         this.config[colIndex].locked = value;
5436         if(!suppressEvent){
5437             this.fireEvent("columnlockchange", this, colIndex, value);
5438         }
5439     },
5440
5441     getTotalLockedWidth : function(){
5442         var totalWidth = 0;
5443         for(var i = 0; i < this.config.length; i++){
5444             if(this.isLocked(i) && !this.isHidden(i)){
5445                 this.totalWidth += this.getColumnWidth(i);
5446             }
5447         }
5448         return totalWidth;
5449     },
5450
5451     getLockedCount : function(){
5452         for(var i = 0, len = this.config.length; i < len; i++){
5453             if(!this.isLocked(i)){
5454                 return i;
5455             }
5456         }
5457         
5458         return this.config.length;
5459     },
5460
5461     /**
5462      * Returns the number of columns.
5463      * @return {Number}
5464      */
5465     getColumnCount : function(visibleOnly){
5466         if(visibleOnly === true){
5467             var c = 0;
5468             for(var i = 0, len = this.config.length; i < len; i++){
5469                 if(!this.isHidden(i)){
5470                     c++;
5471                 }
5472             }
5473             return c;
5474         }
5475         return this.config.length;
5476     },
5477
5478     /**
5479      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5480      * @param {Function} fn
5481      * @param {Object} scope (optional)
5482      * @return {Array} result
5483      */
5484     getColumnsBy : function(fn, scope){
5485         var r = [];
5486         for(var i = 0, len = this.config.length; i < len; i++){
5487             var c = this.config[i];
5488             if(fn.call(scope||this, c, i) === true){
5489                 r[r.length] = c;
5490             }
5491         }
5492         return r;
5493     },
5494
5495     /**
5496      * Returns true if the specified column is sortable.
5497      * @param {Number} col The column index
5498      * @return {Boolean}
5499      */
5500     isSortable : function(col){
5501         if(typeof this.config[col].sortable == "undefined"){
5502             return this.defaultSortable;
5503         }
5504         return this.config[col].sortable;
5505     },
5506
5507     /**
5508      * Returns the rendering (formatting) function defined for the column.
5509      * @param {Number} col The column index.
5510      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5511      */
5512     getRenderer : function(col){
5513         if(!this.config[col].renderer){
5514             return Roo.grid.ColumnModel.defaultRenderer;
5515         }
5516         return this.config[col].renderer;
5517     },
5518
5519     /**
5520      * Sets the rendering (formatting) function for a column.
5521      * @param {Number} col The column index
5522      * @param {Function} fn The function to use to process the cell's raw data
5523      * to return HTML markup for the grid view. The render function is called with
5524      * the following parameters:<ul>
5525      * <li>Data value.</li>
5526      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5527      * <li>css A CSS style string to apply to the table cell.</li>
5528      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5529      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5530      * <li>Row index</li>
5531      * <li>Column index</li>
5532      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5533      */
5534     setRenderer : function(col, fn){
5535         this.config[col].renderer = fn;
5536     },
5537
5538     /**
5539      * Returns the width for the specified column.
5540      * @param {Number} col The column index
5541      * @return {Number}
5542      */
5543     getColumnWidth : function(col){
5544         return this.config[col].width * 1 || this.defaultWidth;
5545     },
5546
5547     /**
5548      * Sets the width for a column.
5549      * @param {Number} col The column index
5550      * @param {Number} width The new width
5551      */
5552     setColumnWidth : function(col, width, suppressEvent){
5553         this.config[col].width = width;
5554         this.totalWidth = null;
5555         if(!suppressEvent){
5556              this.fireEvent("widthchange", this, col, width);
5557         }
5558     },
5559
5560     /**
5561      * Returns the total width of all columns.
5562      * @param {Boolean} includeHidden True to include hidden column widths
5563      * @return {Number}
5564      */
5565     getTotalWidth : function(includeHidden){
5566         if(!this.totalWidth){
5567             this.totalWidth = 0;
5568             for(var i = 0, len = this.config.length; i < len; i++){
5569                 if(includeHidden || !this.isHidden(i)){
5570                     this.totalWidth += this.getColumnWidth(i);
5571                 }
5572             }
5573         }
5574         return this.totalWidth;
5575     },
5576
5577     /**
5578      * Returns the header for the specified column.
5579      * @param {Number} col The column index
5580      * @return {String}
5581      */
5582     getColumnHeader : function(col){
5583         return this.config[col].header;
5584     },
5585
5586     /**
5587      * Sets the header for a column.
5588      * @param {Number} col The column index
5589      * @param {String} header The new header
5590      */
5591     setColumnHeader : function(col, header){
5592         this.config[col].header = header;
5593         this.fireEvent("headerchange", this, col, header);
5594     },
5595
5596     /**
5597      * Returns the tooltip for the specified column.
5598      * @param {Number} col The column index
5599      * @return {String}
5600      */
5601     getColumnTooltip : function(col){
5602             return this.config[col].tooltip;
5603     },
5604     /**
5605      * Sets the tooltip for a column.
5606      * @param {Number} col The column index
5607      * @param {String} tooltip The new tooltip
5608      */
5609     setColumnTooltip : function(col, tooltip){
5610             this.config[col].tooltip = tooltip;
5611     },
5612
5613     /**
5614      * Returns the dataIndex for the specified column.
5615      * @param {Number} col The column index
5616      * @return {Number}
5617      */
5618     getDataIndex : function(col){
5619         return this.config[col].dataIndex;
5620     },
5621
5622     /**
5623      * Sets the dataIndex for a column.
5624      * @param {Number} col The column index
5625      * @param {Number} dataIndex The new dataIndex
5626      */
5627     setDataIndex : function(col, dataIndex){
5628         this.config[col].dataIndex = dataIndex;
5629     },
5630
5631     
5632     
5633     /**
5634      * Returns true if the cell is editable.
5635      * @param {Number} colIndex The column index
5636      * @param {Number} rowIndex The row index - this is nto actually used..?
5637      * @return {Boolean}
5638      */
5639     isCellEditable : function(colIndex, rowIndex){
5640         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5641     },
5642
5643     /**
5644      * Returns the editor defined for the cell/column.
5645      * return false or null to disable editing.
5646      * @param {Number} colIndex The column index
5647      * @param {Number} rowIndex The row index
5648      * @return {Object}
5649      */
5650     getCellEditor : function(colIndex, rowIndex){
5651         return this.config[colIndex].editor;
5652     },
5653
5654     /**
5655      * Sets if a column is editable.
5656      * @param {Number} col The column index
5657      * @param {Boolean} editable True if the column is editable
5658      */
5659     setEditable : function(col, editable){
5660         this.config[col].editable = editable;
5661     },
5662
5663
5664     /**
5665      * Returns true if the column is hidden.
5666      * @param {Number} colIndex The column index
5667      * @return {Boolean}
5668      */
5669     isHidden : function(colIndex){
5670         return this.config[colIndex].hidden;
5671     },
5672
5673
5674     /**
5675      * Returns true if the column width cannot be changed
5676      */
5677     isFixed : function(colIndex){
5678         return this.config[colIndex].fixed;
5679     },
5680
5681     /**
5682      * Returns true if the column can be resized
5683      * @return {Boolean}
5684      */
5685     isResizable : function(colIndex){
5686         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5687     },
5688     /**
5689      * Sets if a column is hidden.
5690      * @param {Number} colIndex The column index
5691      * @param {Boolean} hidden True if the column is hidden
5692      */
5693     setHidden : function(colIndex, hidden){
5694         this.config[colIndex].hidden = hidden;
5695         this.totalWidth = null;
5696         this.fireEvent("hiddenchange", this, colIndex, hidden);
5697     },
5698
5699     /**
5700      * Sets the editor for a column.
5701      * @param {Number} col The column index
5702      * @param {Object} editor The editor object
5703      */
5704     setEditor : function(col, editor){
5705         this.config[col].editor = editor;
5706     }
5707 });
5708
5709 Roo.grid.ColumnModel.defaultRenderer = function(value)
5710 {
5711     if(typeof value == "object") {
5712         return value;
5713     }
5714         if(typeof value == "string" && value.length < 1){
5715             return "&#160;";
5716         }
5717     
5718         return String.format("{0}", value);
5719 };
5720
5721 // Alias for backwards compatibility
5722 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5723 /*
5724  * Based on:
5725  * Ext JS Library 1.1.1
5726  * Copyright(c) 2006-2007, Ext JS, LLC.
5727  *
5728  * Originally Released Under LGPL - original licence link has changed is not relivant.
5729  *
5730  * Fork - LGPL
5731  * <script type="text/javascript">
5732  */
5733  
5734 /**
5735  * @class Roo.LoadMask
5736  * A simple utility class for generically masking elements while loading data.  If the element being masked has
5737  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5738  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
5739  * element's UpdateManager load indicator and will be destroyed after the initial load.
5740  * @constructor
5741  * Create a new LoadMask
5742  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5743  * @param {Object} config The config object
5744  */
5745 Roo.LoadMask = function(el, config){
5746     this.el = Roo.get(el);
5747     Roo.apply(this, config);
5748     if(this.store){
5749         this.store.on('beforeload', this.onBeforeLoad, this);
5750         this.store.on('load', this.onLoad, this);
5751         this.store.on('loadexception', this.onLoadException, this);
5752         this.removeMask = false;
5753     }else{
5754         var um = this.el.getUpdateManager();
5755         um.showLoadIndicator = false; // disable the default indicator
5756         um.on('beforeupdate', this.onBeforeLoad, this);
5757         um.on('update', this.onLoad, this);
5758         um.on('failure', this.onLoad, this);
5759         this.removeMask = true;
5760     }
5761 };
5762
5763 Roo.LoadMask.prototype = {
5764     /**
5765      * @cfg {Boolean} removeMask
5766      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5767      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
5768      */
5769     /**
5770      * @cfg {String} msg
5771      * The text to display in a centered loading message box (defaults to 'Loading...')
5772      */
5773     msg : 'Loading...',
5774     /**
5775      * @cfg {String} msgCls
5776      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5777      */
5778     msgCls : 'x-mask-loading',
5779
5780     /**
5781      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5782      * @type Boolean
5783      */
5784     disabled: false,
5785
5786     /**
5787      * Disables the mask to prevent it from being displayed
5788      */
5789     disable : function(){
5790        this.disabled = true;
5791     },
5792
5793     /**
5794      * Enables the mask so that it can be displayed
5795      */
5796     enable : function(){
5797         this.disabled = false;
5798     },
5799     
5800     onLoadException : function()
5801     {
5802         Roo.log(arguments);
5803         
5804         if (typeof(arguments[3]) != 'undefined') {
5805             Roo.MessageBox.alert("Error loading",arguments[3]);
5806         } 
5807         /*
5808         try {
5809             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5810                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5811             }   
5812         } catch(e) {
5813             
5814         }
5815         */
5816     
5817         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5818     },
5819     // private
5820     onLoad : function()
5821     {
5822         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5823     },
5824
5825     // private
5826     onBeforeLoad : function(){
5827         if(!this.disabled){
5828             (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5829         }
5830     },
5831
5832     // private
5833     destroy : function(){
5834         if(this.store){
5835             this.store.un('beforeload', this.onBeforeLoad, this);
5836             this.store.un('load', this.onLoad, this);
5837             this.store.un('loadexception', this.onLoadException, this);
5838         }else{
5839             var um = this.el.getUpdateManager();
5840             um.un('beforeupdate', this.onBeforeLoad, this);
5841             um.un('update', this.onLoad, this);
5842             um.un('failure', this.onLoad, this);
5843         }
5844     }
5845 };/*
5846  * - LGPL
5847  *
5848  * table
5849  * 
5850  */
5851
5852 /**
5853  * @class Roo.bootstrap.Table
5854  * @extends Roo.bootstrap.Component
5855  * Bootstrap Table class
5856  * @cfg {String} cls table class
5857  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5858  * @cfg {String} bgcolor Specifies the background color for a table
5859  * @cfg {Number} border Specifies whether the table cells should have borders or not
5860  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5861  * @cfg {Number} cellspacing Specifies the space between cells
5862  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5863  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5864  * @cfg {String} sortable Specifies that the table should be sortable
5865  * @cfg {String} summary Specifies a summary of the content of a table
5866  * @cfg {Number} width Specifies the width of a table
5867  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5868  * 
5869  * @cfg {boolean} striped Should the rows be alternative striped
5870  * @cfg {boolean} bordered Add borders to the table
5871  * @cfg {boolean} hover Add hover highlighting
5872  * @cfg {boolean} condensed Format condensed
5873  * @cfg {boolean} responsive Format condensed
5874  * @cfg {Boolean} loadMask (true|false) default false
5875  * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5876  * @cfg {Boolean} headerShow (true|false) generate thead, default true
5877  * @cfg {Boolean} rowSelection (true|false) default false
5878  * @cfg {Boolean} cellSelection (true|false) default false
5879  * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5880  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5881  * @cfg {Boolean} lazyLoad  auto load data while scrolling to the end (default false)
5882  
5883  * 
5884  * @constructor
5885  * Create a new Table
5886  * @param {Object} config The config object
5887  */
5888
5889 Roo.bootstrap.Table = function(config){
5890     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5891     
5892   
5893     
5894     // BC...
5895     this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5896     this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5897     this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5898     this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5899     
5900     this.sm = this.sm || {xtype: 'RowSelectionModel'};
5901     if (this.sm) {
5902         this.sm.grid = this;
5903         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5904         this.sm = this.selModel;
5905         this.sm.xmodule = this.xmodule || false;
5906     }
5907     
5908     if (this.cm && typeof(this.cm.config) == 'undefined') {
5909         this.colModel = new Roo.grid.ColumnModel(this.cm);
5910         this.cm = this.colModel;
5911         this.cm.xmodule = this.xmodule || false;
5912     }
5913     if (this.store) {
5914         this.store= Roo.factory(this.store, Roo.data);
5915         this.ds = this.store;
5916         this.ds.xmodule = this.xmodule || false;
5917          
5918     }
5919     if (this.footer && this.store) {
5920         this.footer.dataSource = this.ds;
5921         this.footer = Roo.factory(this.footer);
5922     }
5923     
5924     /** @private */
5925     this.addEvents({
5926         /**
5927          * @event cellclick
5928          * Fires when a cell is clicked
5929          * @param {Roo.bootstrap.Table} this
5930          * @param {Roo.Element} el
5931          * @param {Number} rowIndex
5932          * @param {Number} columnIndex
5933          * @param {Roo.EventObject} e
5934          */
5935         "cellclick" : true,
5936         /**
5937          * @event celldblclick
5938          * Fires when a cell is double clicked
5939          * @param {Roo.bootstrap.Table} this
5940          * @param {Roo.Element} el
5941          * @param {Number} rowIndex
5942          * @param {Number} columnIndex
5943          * @param {Roo.EventObject} e
5944          */
5945         "celldblclick" : true,
5946         /**
5947          * @event rowclick
5948          * Fires when a row is clicked
5949          * @param {Roo.bootstrap.Table} this
5950          * @param {Roo.Element} el
5951          * @param {Number} rowIndex
5952          * @param {Roo.EventObject} e
5953          */
5954         "rowclick" : true,
5955         /**
5956          * @event rowdblclick
5957          * Fires when a row is double clicked
5958          * @param {Roo.bootstrap.Table} this
5959          * @param {Roo.Element} el
5960          * @param {Number} rowIndex
5961          * @param {Roo.EventObject} e
5962          */
5963         "rowdblclick" : true,
5964         /**
5965          * @event mouseover
5966          * Fires when a mouseover occur
5967          * @param {Roo.bootstrap.Table} this
5968          * @param {Roo.Element} el
5969          * @param {Number} rowIndex
5970          * @param {Number} columnIndex
5971          * @param {Roo.EventObject} e
5972          */
5973         "mouseover" : true,
5974         /**
5975          * @event mouseout
5976          * Fires when a mouseout occur
5977          * @param {Roo.bootstrap.Table} this
5978          * @param {Roo.Element} el
5979          * @param {Number} rowIndex
5980          * @param {Number} columnIndex
5981          * @param {Roo.EventObject} e
5982          */
5983         "mouseout" : true,
5984         /**
5985          * @event rowclass
5986          * Fires when a row is rendered, so you can change add a style to it.
5987          * @param {Roo.bootstrap.Table} this
5988          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5989          */
5990         'rowclass' : true,
5991           /**
5992          * @event rowsrendered
5993          * Fires when all the  rows have been rendered
5994          * @param {Roo.bootstrap.Table} this
5995          */
5996         'rowsrendered' : true,
5997         /**
5998          * @event contextmenu
5999          * The raw contextmenu event for the entire grid.
6000          * @param {Roo.EventObject} e
6001          */
6002         "contextmenu" : true,
6003         /**
6004          * @event rowcontextmenu
6005          * Fires when a row is right clicked
6006          * @param {Roo.bootstrap.Table} this
6007          * @param {Number} rowIndex
6008          * @param {Roo.EventObject} e
6009          */
6010         "rowcontextmenu" : true,
6011         /**
6012          * @event cellcontextmenu
6013          * Fires when a cell is right clicked
6014          * @param {Roo.bootstrap.Table} this
6015          * @param {Number} rowIndex
6016          * @param {Number} cellIndex
6017          * @param {Roo.EventObject} e
6018          */
6019          "cellcontextmenu" : true,
6020          /**
6021          * @event headercontextmenu
6022          * Fires when a header is right clicked
6023          * @param {Roo.bootstrap.Table} this
6024          * @param {Number} columnIndex
6025          * @param {Roo.EventObject} e
6026          */
6027         "headercontextmenu" : true
6028     });
6029 };
6030
6031 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
6032     
6033     cls: false,
6034     align: false,
6035     bgcolor: false,
6036     border: false,
6037     cellpadding: false,
6038     cellspacing: false,
6039     frame: false,
6040     rules: false,
6041     sortable: false,
6042     summary: false,
6043     width: false,
6044     striped : false,
6045     scrollBody : false,
6046     bordered: false,
6047     hover:  false,
6048     condensed : false,
6049     responsive : false,
6050     sm : false,
6051     cm : false,
6052     store : false,
6053     loadMask : false,
6054     footerShow : true,
6055     headerShow : true,
6056   
6057     rowSelection : false,
6058     cellSelection : false,
6059     layout : false,
6060     
6061     // Roo.Element - the tbody
6062     mainBody: false,
6063     // Roo.Element - thead element
6064     mainHead: false,
6065     
6066     container: false, // used by gridpanel...
6067     
6068     lazyLoad : false,
6069     
6070     CSS : Roo.util.CSS,
6071     
6072     getAutoCreate : function()
6073     {
6074         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6075         
6076         cfg = {
6077             tag: 'table',
6078             cls : 'table',
6079             cn : []
6080         };
6081         if (this.scrollBody) {
6082             cfg.cls += ' table-body-fixed';
6083         }    
6084         if (this.striped) {
6085             cfg.cls += ' table-striped';
6086         }
6087         
6088         if (this.hover) {
6089             cfg.cls += ' table-hover';
6090         }
6091         if (this.bordered) {
6092             cfg.cls += ' table-bordered';
6093         }
6094         if (this.condensed) {
6095             cfg.cls += ' table-condensed';
6096         }
6097         if (this.responsive) {
6098             cfg.cls += ' table-responsive';
6099         }
6100         
6101         if (this.cls) {
6102             cfg.cls+=  ' ' +this.cls;
6103         }
6104         
6105         // this lot should be simplifed...
6106         var _t = this;
6107         var cp = [
6108             'align',
6109             'bgcolor',
6110             'border',
6111             'cellpadding',
6112             'cellspacing',
6113             'frame',
6114             'rules',
6115             'sortable',
6116             'summary',
6117             'width'
6118         ].forEach(function(k) {
6119             if (_t[k]) {
6120                 cfg[k] = _t[k];
6121             }
6122         });
6123         
6124         
6125         if (this.layout) {
6126             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6127         }
6128         
6129         if(this.store || this.cm){
6130             if(this.headerShow){
6131                 cfg.cn.push(this.renderHeader());
6132             }
6133             
6134             cfg.cn.push(this.renderBody());
6135             
6136             if(this.footerShow){
6137                 cfg.cn.push(this.renderFooter());
6138             }
6139             // where does this come from?
6140             //cfg.cls+=  ' TableGrid';
6141         }
6142         
6143         return { cn : [ cfg ] };
6144     },
6145     
6146     initEvents : function()
6147     {   
6148         if(!this.store || !this.cm){
6149             return;
6150         }
6151         if (this.selModel) {
6152             this.selModel.initEvents();
6153         }
6154         
6155         
6156         //Roo.log('initEvents with ds!!!!');
6157         
6158         this.mainBody = this.el.select('tbody', true).first();
6159         this.mainHead = this.el.select('thead', true).first();
6160         
6161         
6162         
6163         
6164         var _this = this;
6165         
6166         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6167             e.on('click', _this.sort, _this);
6168         });
6169         
6170         this.mainBody.on("click", this.onClick, this);
6171         this.mainBody.on("dblclick", this.onDblClick, this);
6172         
6173         // why is this done????? = it breaks dialogs??
6174         //this.parent().el.setStyle('position', 'relative');
6175         
6176         
6177         if (this.footer) {
6178             this.footer.parentId = this.id;
6179             this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6180             
6181             if(this.lazyLoad){
6182                 this.el.select('tfoot tr td').first().addClass('hide');
6183             }
6184         } 
6185         
6186         if(this.loadMask) {
6187             this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6188         }
6189         
6190         this.store.on('load', this.onLoad, this);
6191         this.store.on('beforeload', this.onBeforeLoad, this);
6192         this.store.on('update', this.onUpdate, this);
6193         this.store.on('add', this.onAdd, this);
6194         this.store.on("clear", this.clear, this);
6195         
6196         this.el.on("contextmenu", this.onContextMenu, this);
6197         
6198         this.mainBody.on('scroll', this.onBodyScroll, this);
6199         
6200         this.cm.on("headerchange", this.onHeaderChange, this);
6201         
6202         this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6203         
6204     },
6205     
6206     onContextMenu : function(e, t)
6207     {
6208         this.processEvent("contextmenu", e);
6209     },
6210     
6211     processEvent : function(name, e)
6212     {
6213         if (name != 'touchstart' ) {
6214             this.fireEvent(name, e);    
6215         }
6216         
6217         var t = e.getTarget();
6218         
6219         var cell = Roo.get(t);
6220         
6221         if(!cell){
6222             return;
6223         }
6224         
6225         if(cell.findParent('tfoot', false, true)){
6226             return;
6227         }
6228         
6229         if(cell.findParent('thead', false, true)){
6230             
6231             if(e.getTarget().nodeName.toLowerCase() != 'th'){
6232                 cell = Roo.get(t).findParent('th', false, true);
6233                 if (!cell) {
6234                     Roo.log("failed to find th in thead?");
6235                     Roo.log(e.getTarget());
6236                     return;
6237                 }
6238             }
6239             
6240             var cellIndex = cell.dom.cellIndex;
6241             
6242             var ename = name == 'touchstart' ? 'click' : name;
6243             this.fireEvent("header" + ename, this, cellIndex, e);
6244             
6245             return;
6246         }
6247         
6248         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6249             cell = Roo.get(t).findParent('td', false, true);
6250             if (!cell) {
6251                 Roo.log("failed to find th in tbody?");
6252                 Roo.log(e.getTarget());
6253                 return;
6254             }
6255         }
6256         
6257         var row = cell.findParent('tr', false, true);
6258         var cellIndex = cell.dom.cellIndex;
6259         var rowIndex = row.dom.rowIndex - 1;
6260         
6261         if(row !== false){
6262             
6263             this.fireEvent("row" + name, this, rowIndex, e);
6264             
6265             if(cell !== false){
6266             
6267                 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6268             }
6269         }
6270         
6271     },
6272     
6273     onMouseover : function(e, el)
6274     {
6275         var cell = Roo.get(el);
6276         
6277         if(!cell){
6278             return;
6279         }
6280         
6281         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6282             cell = cell.findParent('td', false, true);
6283         }
6284         
6285         var row = cell.findParent('tr', false, true);
6286         var cellIndex = cell.dom.cellIndex;
6287         var rowIndex = row.dom.rowIndex - 1; // start from 0
6288         
6289         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6290         
6291     },
6292     
6293     onMouseout : function(e, el)
6294     {
6295         var cell = Roo.get(el);
6296         
6297         if(!cell){
6298             return;
6299         }
6300         
6301         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6302             cell = cell.findParent('td', false, true);
6303         }
6304         
6305         var row = cell.findParent('tr', false, true);
6306         var cellIndex = cell.dom.cellIndex;
6307         var rowIndex = row.dom.rowIndex - 1; // start from 0
6308         
6309         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6310         
6311     },
6312     
6313     onClick : function(e, el)
6314     {
6315         var cell = Roo.get(el);
6316         
6317         if(!cell || (!this.cellSelection && !this.rowSelection)){
6318             return;
6319         }
6320         
6321         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6322             cell = cell.findParent('td', false, true);
6323         }
6324         
6325         if(!cell || typeof(cell) == 'undefined'){
6326             return;
6327         }
6328         
6329         var row = cell.findParent('tr', false, true);
6330         
6331         if(!row || typeof(row) == 'undefined'){
6332             return;
6333         }
6334         
6335         var cellIndex = cell.dom.cellIndex;
6336         var rowIndex = this.getRowIndex(row);
6337         
6338         // why??? - should these not be based on SelectionModel?
6339         if(this.cellSelection){
6340             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6341         }
6342         
6343         if(this.rowSelection){
6344             this.fireEvent('rowclick', this, row, rowIndex, e);
6345         }
6346         
6347         
6348     },
6349         
6350     onDblClick : function(e,el)
6351     {
6352         var cell = Roo.get(el);
6353         
6354         if(!cell || (!this.cellSelection && !this.rowSelection)){
6355             return;
6356         }
6357         
6358         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6359             cell = cell.findParent('td', false, true);
6360         }
6361         
6362         if(!cell || typeof(cell) == 'undefined'){
6363             return;
6364         }
6365         
6366         var row = cell.findParent('tr', false, true);
6367         
6368         if(!row || typeof(row) == 'undefined'){
6369             return;
6370         }
6371         
6372         var cellIndex = cell.dom.cellIndex;
6373         var rowIndex = this.getRowIndex(row);
6374         
6375         if(this.cellSelection){
6376             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6377         }
6378         
6379         if(this.rowSelection){
6380             this.fireEvent('rowdblclick', this, row, rowIndex, e);
6381         }
6382     },
6383     
6384     sort : function(e,el)
6385     {
6386         var col = Roo.get(el);
6387         
6388         if(!col.hasClass('sortable')){
6389             return;
6390         }
6391         
6392         var sort = col.attr('sort');
6393         var dir = 'ASC';
6394         
6395         if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6396             dir = 'DESC';
6397         }
6398         
6399         this.store.sortInfo = {field : sort, direction : dir};
6400         
6401         if (this.footer) {
6402             Roo.log("calling footer first");
6403             this.footer.onClick('first');
6404         } else {
6405         
6406             this.store.load({ params : { start : 0 } });
6407         }
6408     },
6409     
6410     renderHeader : function()
6411     {
6412         var header = {
6413             tag: 'thead',
6414             cn : []
6415         };
6416         
6417         var cm = this.cm;
6418         this.totalWidth = 0;
6419         
6420         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6421             
6422             var config = cm.config[i];
6423             
6424             var c = {
6425                 tag: 'th',
6426                 cls : 'x-hcol-' + i,
6427                 style : '',
6428                 html: cm.getColumnHeader(i)
6429             };
6430             
6431             var hh = '';
6432             
6433             if(typeof(config.sortable) != 'undefined' && config.sortable){
6434                 c.cls = 'sortable';
6435                 c.html = '<i class="glyphicon"></i>' + c.html;
6436             }
6437             
6438             if(typeof(config.lgHeader) != 'undefined'){
6439                 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6440             }
6441             
6442             if(typeof(config.mdHeader) != 'undefined'){
6443                 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6444             }
6445             
6446             if(typeof(config.smHeader) != 'undefined'){
6447                 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6448             }
6449             
6450             if(typeof(config.xsHeader) != 'undefined'){
6451                 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6452             }
6453             
6454             if(hh.length){
6455                 c.html = hh;
6456             }
6457             
6458             if(typeof(config.tooltip) != 'undefined'){
6459                 c.tooltip = config.tooltip;
6460             }
6461             
6462             if(typeof(config.colspan) != 'undefined'){
6463                 c.colspan = config.colspan;
6464             }
6465             
6466             if(typeof(config.hidden) != 'undefined' && config.hidden){
6467                 c.style += ' display:none;';
6468             }
6469             
6470             if(typeof(config.dataIndex) != 'undefined'){
6471                 c.sort = config.dataIndex;
6472             }
6473             
6474            
6475             
6476             if(typeof(config.align) != 'undefined' && config.align.length){
6477                 c.style += ' text-align:' + config.align + ';';
6478             }
6479             
6480             if(typeof(config.width) != 'undefined'){
6481                 c.style += ' width:' + config.width + 'px;';
6482                 this.totalWidth += config.width;
6483             } else {
6484                 this.totalWidth += 100; // assume minimum of 100 per column?
6485             }
6486             
6487             if(typeof(config.cls) != 'undefined'){
6488                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6489             }
6490             
6491             ['xs','sm','md','lg'].map(function(size){
6492                 
6493                 if(typeof(config[size]) == 'undefined'){
6494                     return;
6495                 }
6496                 
6497                 if (!config[size]) { // 0 = hidden
6498                     c.cls += ' hidden-' + size;
6499                     return;
6500                 }
6501                 
6502                 c.cls += ' col-' + size + '-' + config[size];
6503
6504             });
6505             
6506             header.cn.push(c)
6507         }
6508         
6509         return header;
6510     },
6511     
6512     renderBody : function()
6513     {
6514         var body = {
6515             tag: 'tbody',
6516             cn : [
6517                 {
6518                     tag: 'tr',
6519                     cn : [
6520                         {
6521                             tag : 'td',
6522                             colspan :  this.cm.getColumnCount()
6523                         }
6524                     ]
6525                 }
6526             ]
6527         };
6528         
6529         return body;
6530     },
6531     
6532     renderFooter : function()
6533     {
6534         var footer = {
6535             tag: 'tfoot',
6536             cn : [
6537                 {
6538                     tag: 'tr',
6539                     cn : [
6540                         {
6541                             tag : 'td',
6542                             colspan :  this.cm.getColumnCount()
6543                         }
6544                     ]
6545                 }
6546             ]
6547         };
6548         
6549         return footer;
6550     },
6551     
6552     
6553     
6554     onLoad : function()
6555     {
6556 //        Roo.log('ds onload');
6557         this.clear();
6558         
6559         var _this = this;
6560         var cm = this.cm;
6561         var ds = this.store;
6562         
6563         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6564             e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6565             if (_this.store.sortInfo) {
6566                     
6567                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6568                     e.select('i', true).addClass(['glyphicon-arrow-up']);
6569                 }
6570                 
6571                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6572                     e.select('i', true).addClass(['glyphicon-arrow-down']);
6573                 }
6574             }
6575         });
6576         
6577         var tbody =  this.mainBody;
6578               
6579         if(ds.getCount() > 0){
6580             ds.data.each(function(d,rowIndex){
6581                 var row =  this.renderRow(cm, ds, rowIndex);
6582                 
6583                 tbody.createChild(row);
6584                 
6585                 var _this = this;
6586                 
6587                 if(row.cellObjects.length){
6588                     Roo.each(row.cellObjects, function(r){
6589                         _this.renderCellObject(r);
6590                     })
6591                 }
6592                 
6593             }, this);
6594         }
6595         
6596         Roo.each(this.el.select('tbody td', true).elements, function(e){
6597             e.on('mouseover', _this.onMouseover, _this);
6598         });
6599         
6600         Roo.each(this.el.select('tbody td', true).elements, function(e){
6601             e.on('mouseout', _this.onMouseout, _this);
6602         });
6603         this.fireEvent('rowsrendered', this);
6604         
6605         this.autoSize();
6606     },
6607     
6608     
6609     onUpdate : function(ds,record)
6610     {
6611         this.refreshRow(record);
6612         this.autoSize();
6613     },
6614     
6615     onRemove : function(ds, record, index, isUpdate){
6616         if(isUpdate !== true){
6617             this.fireEvent("beforerowremoved", this, index, record);
6618         }
6619         var bt = this.mainBody.dom;
6620         
6621         var rows = this.el.select('tbody > tr', true).elements;
6622         
6623         if(typeof(rows[index]) != 'undefined'){
6624             bt.removeChild(rows[index].dom);
6625         }
6626         
6627 //        if(bt.rows[index]){
6628 //            bt.removeChild(bt.rows[index]);
6629 //        }
6630         
6631         if(isUpdate !== true){
6632             //this.stripeRows(index);
6633             //this.syncRowHeights(index, index);
6634             //this.layout();
6635             this.fireEvent("rowremoved", this, index, record);
6636         }
6637     },
6638     
6639     onAdd : function(ds, records, rowIndex)
6640     {
6641         //Roo.log('on Add called');
6642         // - note this does not handle multiple adding very well..
6643         var bt = this.mainBody.dom;
6644         for (var i =0 ; i < records.length;i++) {
6645             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6646             //Roo.log(records[i]);
6647             //Roo.log(this.store.getAt(rowIndex+i));
6648             this.insertRow(this.store, rowIndex + i, false);
6649             return;
6650         }
6651         
6652     },
6653     
6654     
6655     refreshRow : function(record){
6656         var ds = this.store, index;
6657         if(typeof record == 'number'){
6658             index = record;
6659             record = ds.getAt(index);
6660         }else{
6661             index = ds.indexOf(record);
6662         }
6663         this.insertRow(ds, index, true);
6664         this.autoSize();
6665         this.onRemove(ds, record, index+1, true);
6666         this.autoSize();
6667         //this.syncRowHeights(index, index);
6668         //this.layout();
6669         this.fireEvent("rowupdated", this, index, record);
6670     },
6671     
6672     insertRow : function(dm, rowIndex, isUpdate){
6673         
6674         if(!isUpdate){
6675             this.fireEvent("beforerowsinserted", this, rowIndex);
6676         }
6677             //var s = this.getScrollState();
6678         var row = this.renderRow(this.cm, this.store, rowIndex);
6679         // insert before rowIndex..
6680         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6681         
6682         var _this = this;
6683                 
6684         if(row.cellObjects.length){
6685             Roo.each(row.cellObjects, function(r){
6686                 _this.renderCellObject(r);
6687             })
6688         }
6689             
6690         if(!isUpdate){
6691             this.fireEvent("rowsinserted", this, rowIndex);
6692             //this.syncRowHeights(firstRow, lastRow);
6693             //this.stripeRows(firstRow);
6694             //this.layout();
6695         }
6696         
6697     },
6698     
6699     
6700     getRowDom : function(rowIndex)
6701     {
6702         var rows = this.el.select('tbody > tr', true).elements;
6703         
6704         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6705         
6706     },
6707     // returns the object tree for a tr..
6708   
6709     
6710     renderRow : function(cm, ds, rowIndex) 
6711     {
6712         var d = ds.getAt(rowIndex);
6713         
6714         var row = {
6715             tag : 'tr',
6716             cls : 'x-row-' + rowIndex,
6717             cn : []
6718         };
6719             
6720         var cellObjects = [];
6721         
6722         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6723             var config = cm.config[i];
6724             
6725             var renderer = cm.getRenderer(i);
6726             var value = '';
6727             var id = false;
6728             
6729             if(typeof(renderer) !== 'undefined'){
6730                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6731             }
6732             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6733             // and are rendered into the cells after the row is rendered - using the id for the element.
6734             
6735             if(typeof(value) === 'object'){
6736                 id = Roo.id();
6737                 cellObjects.push({
6738                     container : id,
6739                     cfg : value 
6740                 })
6741             }
6742             
6743             var rowcfg = {
6744                 record: d,
6745                 rowIndex : rowIndex,
6746                 colIndex : i,
6747                 rowClass : ''
6748             };
6749
6750             this.fireEvent('rowclass', this, rowcfg);
6751             
6752             var td = {
6753                 tag: 'td',
6754                 cls : rowcfg.rowClass + ' x-col-' + i,
6755                 style: '',
6756                 html: (typeof(value) === 'object') ? '' : value
6757             };
6758             
6759             if (id) {
6760                 td.id = id;
6761             }
6762             
6763             if(typeof(config.colspan) != 'undefined'){
6764                 td.colspan = config.colspan;
6765             }
6766             
6767             if(typeof(config.hidden) != 'undefined' && config.hidden){
6768                 td.style += ' display:none;';
6769             }
6770             
6771             if(typeof(config.align) != 'undefined' && config.align.length){
6772                 td.style += ' text-align:' + config.align + ';';
6773             }
6774             if(typeof(config.valign) != 'undefined' && config.valign.length){
6775                 td.style += ' vertical-align:' + config.valign + ';';
6776             }
6777             
6778             if(typeof(config.width) != 'undefined'){
6779                 td.style += ' width:' +  config.width + 'px;';
6780             }
6781             
6782             if(typeof(config.cursor) != 'undefined'){
6783                 td.style += ' cursor:' +  config.cursor + ';';
6784             }
6785             
6786             if(typeof(config.cls) != 'undefined'){
6787                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6788             }
6789             
6790             ['xs','sm','md','lg'].map(function(size){
6791                 
6792                 if(typeof(config[size]) == 'undefined'){
6793                     return;
6794                 }
6795                 
6796                 if (!config[size]) { // 0 = hidden
6797                     td.cls += ' hidden-' + size;
6798                     return;
6799                 }
6800                 
6801                 td.cls += ' col-' + size + '-' + config[size];
6802
6803             });
6804             
6805             row.cn.push(td);
6806            
6807         }
6808         
6809         row.cellObjects = cellObjects;
6810         
6811         return row;
6812           
6813     },
6814     
6815     
6816     
6817     onBeforeLoad : function()
6818     {
6819         
6820     },
6821      /**
6822      * Remove all rows
6823      */
6824     clear : function()
6825     {
6826         this.el.select('tbody', true).first().dom.innerHTML = '';
6827     },
6828     /**
6829      * Show or hide a row.
6830      * @param {Number} rowIndex to show or hide
6831      * @param {Boolean} state hide
6832      */
6833     setRowVisibility : function(rowIndex, state)
6834     {
6835         var bt = this.mainBody.dom;
6836         
6837         var rows = this.el.select('tbody > tr', true).elements;
6838         
6839         if(typeof(rows[rowIndex]) == 'undefined'){
6840             return;
6841         }
6842         rows[rowIndex].dom.style.display = state ? '' : 'none';
6843     },
6844     
6845     
6846     getSelectionModel : function(){
6847         if(!this.selModel){
6848             this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6849         }
6850         return this.selModel;
6851     },
6852     /*
6853      * Render the Roo.bootstrap object from renderder
6854      */
6855     renderCellObject : function(r)
6856     {
6857         var _this = this;
6858         
6859         r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6860         
6861         var t = r.cfg.render(r.container);
6862         
6863         if(r.cfg.cn){
6864             Roo.each(r.cfg.cn, function(c){
6865                 var child = {
6866                     container: t.getChildContainer(),
6867                     cfg: c
6868                 };
6869                 _this.renderCellObject(child);
6870             })
6871         }
6872     },
6873     
6874     getRowIndex : function(row)
6875     {
6876         var rowIndex = -1;
6877         
6878         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6879             if(el != row){
6880                 return;
6881             }
6882             
6883             rowIndex = index;
6884         });
6885         
6886         return rowIndex;
6887     },
6888      /**
6889      * Returns the grid's underlying element = used by panel.Grid
6890      * @return {Element} The element
6891      */
6892     getGridEl : function(){
6893         return this.el;
6894     },
6895      /**
6896      * Forces a resize - used by panel.Grid
6897      * @return {Element} The element
6898      */
6899     autoSize : function()
6900     {
6901         //var ctr = Roo.get(this.container.dom.parentElement);
6902         var ctr = Roo.get(this.el.dom);
6903         
6904         var thd = this.getGridEl().select('thead',true).first();
6905         var tbd = this.getGridEl().select('tbody', true).first();
6906         var tfd = this.getGridEl().select('tfoot', true).first();
6907         
6908         var cw = ctr.getWidth();
6909         
6910         if (tbd) {
6911             
6912             tbd.setSize(ctr.getWidth(),
6913                         ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6914             );
6915             var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6916             cw -= barsize;
6917         }
6918         cw = Math.max(cw, this.totalWidth);
6919         this.getGridEl().select('tr',true).setWidth(cw);
6920         // resize 'expandable coloumn?
6921         
6922         return; // we doe not have a view in this design..
6923         
6924     },
6925     onBodyScroll: function()
6926     {
6927         //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6928         if(this.mainHead){
6929             this.mainHead.setStyle({
6930                 'position' : 'relative',
6931                 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6932             });
6933         }
6934         
6935         if(this.lazyLoad){
6936             
6937             var scrollHeight = this.mainBody.dom.scrollHeight;
6938             
6939             var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6940             
6941             var height = this.mainBody.getHeight();
6942             
6943             if(scrollHeight - height == scrollTop) {
6944                 
6945                 var total = this.ds.getTotalCount();
6946                 
6947                 if(this.footer.cursor + this.footer.pageSize < total){
6948                     
6949                     this.footer.ds.load({
6950                         params : {
6951                             start : this.footer.cursor + this.footer.pageSize,
6952                             limit : this.footer.pageSize
6953                         },
6954                         add : true
6955                     });
6956                 }
6957             }
6958             
6959         }
6960     },
6961     
6962     onHeaderChange : function()
6963     {
6964         var header = this.renderHeader();
6965         var table = this.el.select('table', true).first();
6966         
6967         this.mainHead.remove();
6968         this.mainHead = table.createChild(header, this.mainBody, false);
6969     },
6970     
6971     onHiddenChange : function(colModel, colIndex, hidden)
6972     {
6973         var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6974         var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6975         
6976         this.CSS.updateRule(thSelector, "display", "");
6977         this.CSS.updateRule(tdSelector, "display", "");
6978         
6979         if(hidden){
6980             this.CSS.updateRule(thSelector, "display", "none");
6981             this.CSS.updateRule(tdSelector, "display", "none");
6982         }
6983         
6984         this.onHeaderChange();
6985         this.onLoad();
6986         
6987     }
6988     
6989 });
6990
6991  
6992
6993  /*
6994  * - LGPL
6995  *
6996  * table cell
6997  * 
6998  */
6999
7000 /**
7001  * @class Roo.bootstrap.TableCell
7002  * @extends Roo.bootstrap.Component
7003  * Bootstrap TableCell class
7004  * @cfg {String} html cell contain text
7005  * @cfg {String} cls cell class
7006  * @cfg {String} tag cell tag (td|th) default td
7007  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7008  * @cfg {String} align Aligns the content in a cell
7009  * @cfg {String} axis Categorizes cells
7010  * @cfg {String} bgcolor Specifies the background color of a cell
7011  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7012  * @cfg {Number} colspan Specifies the number of columns a cell should span
7013  * @cfg {String} headers Specifies one or more header cells a cell is related to
7014  * @cfg {Number} height Sets the height of a cell
7015  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7016  * @cfg {Number} rowspan Sets the number of rows a cell should span
7017  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7018  * @cfg {String} valign Vertical aligns the content in a cell
7019  * @cfg {Number} width Specifies the width of a cell
7020  * 
7021  * @constructor
7022  * Create a new TableCell
7023  * @param {Object} config The config object
7024  */
7025
7026 Roo.bootstrap.TableCell = function(config){
7027     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7028 };
7029
7030 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
7031     
7032     html: false,
7033     cls: false,
7034     tag: false,
7035     abbr: false,
7036     align: false,
7037     axis: false,
7038     bgcolor: false,
7039     charoff: false,
7040     colspan: false,
7041     headers: false,
7042     height: false,
7043     nowrap: false,
7044     rowspan: false,
7045     scope: false,
7046     valign: false,
7047     width: false,
7048     
7049     
7050     getAutoCreate : function(){
7051         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7052         
7053         cfg = {
7054             tag: 'td'
7055         };
7056         
7057         if(this.tag){
7058             cfg.tag = this.tag;
7059         }
7060         
7061         if (this.html) {
7062             cfg.html=this.html
7063         }
7064         if (this.cls) {
7065             cfg.cls=this.cls
7066         }
7067         if (this.abbr) {
7068             cfg.abbr=this.abbr
7069         }
7070         if (this.align) {
7071             cfg.align=this.align
7072         }
7073         if (this.axis) {
7074             cfg.axis=this.axis
7075         }
7076         if (this.bgcolor) {
7077             cfg.bgcolor=this.bgcolor
7078         }
7079         if (this.charoff) {
7080             cfg.charoff=this.charoff
7081         }
7082         if (this.colspan) {
7083             cfg.colspan=this.colspan
7084         }
7085         if (this.headers) {
7086             cfg.headers=this.headers
7087         }
7088         if (this.height) {
7089             cfg.height=this.height
7090         }
7091         if (this.nowrap) {
7092             cfg.nowrap=this.nowrap
7093         }
7094         if (this.rowspan) {
7095             cfg.rowspan=this.rowspan
7096         }
7097         if (this.scope) {
7098             cfg.scope=this.scope
7099         }
7100         if (this.valign) {
7101             cfg.valign=this.valign
7102         }
7103         if (this.width) {
7104             cfg.width=this.width
7105         }
7106         
7107         
7108         return cfg;
7109     }
7110    
7111 });
7112
7113  
7114
7115  /*
7116  * - LGPL
7117  *
7118  * table row
7119  * 
7120  */
7121
7122 /**
7123  * @class Roo.bootstrap.TableRow
7124  * @extends Roo.bootstrap.Component
7125  * Bootstrap TableRow class
7126  * @cfg {String} cls row class
7127  * @cfg {String} align Aligns the content in a table row
7128  * @cfg {String} bgcolor Specifies a background color for a table row
7129  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7130  * @cfg {String} valign Vertical aligns the content in a table row
7131  * 
7132  * @constructor
7133  * Create a new TableRow
7134  * @param {Object} config The config object
7135  */
7136
7137 Roo.bootstrap.TableRow = function(config){
7138     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7139 };
7140
7141 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
7142     
7143     cls: false,
7144     align: false,
7145     bgcolor: false,
7146     charoff: false,
7147     valign: false,
7148     
7149     getAutoCreate : function(){
7150         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7151         
7152         cfg = {
7153             tag: 'tr'
7154         };
7155             
7156         if(this.cls){
7157             cfg.cls = this.cls;
7158         }
7159         if(this.align){
7160             cfg.align = this.align;
7161         }
7162         if(this.bgcolor){
7163             cfg.bgcolor = this.bgcolor;
7164         }
7165         if(this.charoff){
7166             cfg.charoff = this.charoff;
7167         }
7168         if(this.valign){
7169             cfg.valign = this.valign;
7170         }
7171         
7172         return cfg;
7173     }
7174    
7175 });
7176
7177  
7178
7179  /*
7180  * - LGPL
7181  *
7182  * table body
7183  * 
7184  */
7185
7186 /**
7187  * @class Roo.bootstrap.TableBody
7188  * @extends Roo.bootstrap.Component
7189  * Bootstrap TableBody class
7190  * @cfg {String} cls element class
7191  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7192  * @cfg {String} align Aligns the content inside the element
7193  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7194  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7195  * 
7196  * @constructor
7197  * Create a new TableBody
7198  * @param {Object} config The config object
7199  */
7200
7201 Roo.bootstrap.TableBody = function(config){
7202     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7203 };
7204
7205 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
7206     
7207     cls: false,
7208     tag: false,
7209     align: false,
7210     charoff: false,
7211     valign: false,
7212     
7213     getAutoCreate : function(){
7214         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7215         
7216         cfg = {
7217             tag: 'tbody'
7218         };
7219             
7220         if (this.cls) {
7221             cfg.cls=this.cls
7222         }
7223         if(this.tag){
7224             cfg.tag = this.tag;
7225         }
7226         
7227         if(this.align){
7228             cfg.align = this.align;
7229         }
7230         if(this.charoff){
7231             cfg.charoff = this.charoff;
7232         }
7233         if(this.valign){
7234             cfg.valign = this.valign;
7235         }
7236         
7237         return cfg;
7238     }
7239     
7240     
7241 //    initEvents : function()
7242 //    {
7243 //        
7244 //        if(!this.store){
7245 //            return;
7246 //        }
7247 //        
7248 //        this.store = Roo.factory(this.store, Roo.data);
7249 //        this.store.on('load', this.onLoad, this);
7250 //        
7251 //        this.store.load();
7252 //        
7253 //    },
7254 //    
7255 //    onLoad: function () 
7256 //    {   
7257 //        this.fireEvent('load', this);
7258 //    }
7259 //    
7260 //   
7261 });
7262
7263  
7264
7265  /*
7266  * Based on:
7267  * Ext JS Library 1.1.1
7268  * Copyright(c) 2006-2007, Ext JS, LLC.
7269  *
7270  * Originally Released Under LGPL - original licence link has changed is not relivant.
7271  *
7272  * Fork - LGPL
7273  * <script type="text/javascript">
7274  */
7275
7276 // as we use this in bootstrap.
7277 Roo.namespace('Roo.form');
7278  /**
7279  * @class Roo.form.Action
7280  * Internal Class used to handle form actions
7281  * @constructor
7282  * @param {Roo.form.BasicForm} el The form element or its id
7283  * @param {Object} config Configuration options
7284  */
7285
7286  
7287  
7288 // define the action interface
7289 Roo.form.Action = function(form, options){
7290     this.form = form;
7291     this.options = options || {};
7292 };
7293 /**
7294  * Client Validation Failed
7295  * @const 
7296  */
7297 Roo.form.Action.CLIENT_INVALID = 'client';
7298 /**
7299  * Server Validation Failed
7300  * @const 
7301  */
7302 Roo.form.Action.SERVER_INVALID = 'server';
7303  /**
7304  * Connect to Server Failed
7305  * @const 
7306  */
7307 Roo.form.Action.CONNECT_FAILURE = 'connect';
7308 /**
7309  * Reading Data from Server Failed
7310  * @const 
7311  */
7312 Roo.form.Action.LOAD_FAILURE = 'load';
7313
7314 Roo.form.Action.prototype = {
7315     type : 'default',
7316     failureType : undefined,
7317     response : undefined,
7318     result : undefined,
7319
7320     // interface method
7321     run : function(options){
7322
7323     },
7324
7325     // interface method
7326     success : function(response){
7327
7328     },
7329
7330     // interface method
7331     handleResponse : function(response){
7332
7333     },
7334
7335     // default connection failure
7336     failure : function(response){
7337         
7338         this.response = response;
7339         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7340         this.form.afterAction(this, false);
7341     },
7342
7343     processResponse : function(response){
7344         this.response = response;
7345         if(!response.responseText){
7346             return true;
7347         }
7348         this.result = this.handleResponse(response);
7349         return this.result;
7350     },
7351
7352     // utility functions used internally
7353     getUrl : function(appendParams){
7354         var url = this.options.url || this.form.url || this.form.el.dom.action;
7355         if(appendParams){
7356             var p = this.getParams();
7357             if(p){
7358                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7359             }
7360         }
7361         return url;
7362     },
7363
7364     getMethod : function(){
7365         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7366     },
7367
7368     getParams : function(){
7369         var bp = this.form.baseParams;
7370         var p = this.options.params;
7371         if(p){
7372             if(typeof p == "object"){
7373                 p = Roo.urlEncode(Roo.applyIf(p, bp));
7374             }else if(typeof p == 'string' && bp){
7375                 p += '&' + Roo.urlEncode(bp);
7376             }
7377         }else if(bp){
7378             p = Roo.urlEncode(bp);
7379         }
7380         return p;
7381     },
7382
7383     createCallback : function(){
7384         return {
7385             success: this.success,
7386             failure: this.failure,
7387             scope: this,
7388             timeout: (this.form.timeout*1000),
7389             upload: this.form.fileUpload ? this.success : undefined
7390         };
7391     }
7392 };
7393
7394 Roo.form.Action.Submit = function(form, options){
7395     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7396 };
7397
7398 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7399     type : 'submit',
7400
7401     haveProgress : false,
7402     uploadComplete : false,
7403     
7404     // uploadProgress indicator.
7405     uploadProgress : function()
7406     {
7407         if (!this.form.progressUrl) {
7408             return;
7409         }
7410         
7411         if (!this.haveProgress) {
7412             Roo.MessageBox.progress("Uploading", "Uploading");
7413         }
7414         if (this.uploadComplete) {
7415            Roo.MessageBox.hide();
7416            return;
7417         }
7418         
7419         this.haveProgress = true;
7420    
7421         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7422         
7423         var c = new Roo.data.Connection();
7424         c.request({
7425             url : this.form.progressUrl,
7426             params: {
7427                 id : uid
7428             },
7429             method: 'GET',
7430             success : function(req){
7431                //console.log(data);
7432                 var rdata = false;
7433                 var edata;
7434                 try  {
7435                    rdata = Roo.decode(req.responseText)
7436                 } catch (e) {
7437                     Roo.log("Invalid data from server..");
7438                     Roo.log(edata);
7439                     return;
7440                 }
7441                 if (!rdata || !rdata.success) {
7442                     Roo.log(rdata);
7443                     Roo.MessageBox.alert(Roo.encode(rdata));
7444                     return;
7445                 }
7446                 var data = rdata.data;
7447                 
7448                 if (this.uploadComplete) {
7449                    Roo.MessageBox.hide();
7450                    return;
7451                 }
7452                    
7453                 if (data){
7454                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7455                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7456                     );
7457                 }
7458                 this.uploadProgress.defer(2000,this);
7459             },
7460        
7461             failure: function(data) {
7462                 Roo.log('progress url failed ');
7463                 Roo.log(data);
7464             },
7465             scope : this
7466         });
7467            
7468     },
7469     
7470     
7471     run : function()
7472     {
7473         // run get Values on the form, so it syncs any secondary forms.
7474         this.form.getValues();
7475         
7476         var o = this.options;
7477         var method = this.getMethod();
7478         var isPost = method == 'POST';
7479         if(o.clientValidation === false || this.form.isValid()){
7480             
7481             if (this.form.progressUrl) {
7482                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7483                     (new Date() * 1) + '' + Math.random());
7484                     
7485             } 
7486             
7487             
7488             Roo.Ajax.request(Roo.apply(this.createCallback(), {
7489                 form:this.form.el.dom,
7490                 url:this.getUrl(!isPost),
7491                 method: method,
7492                 params:isPost ? this.getParams() : null,
7493                 isUpload: this.form.fileUpload
7494             }));
7495             
7496             this.uploadProgress();
7497
7498         }else if (o.clientValidation !== false){ // client validation failed
7499             this.failureType = Roo.form.Action.CLIENT_INVALID;
7500             this.form.afterAction(this, false);
7501         }
7502     },
7503
7504     success : function(response)
7505     {
7506         this.uploadComplete= true;
7507         if (this.haveProgress) {
7508             Roo.MessageBox.hide();
7509         }
7510         
7511         
7512         var result = this.processResponse(response);
7513         if(result === true || result.success){
7514             this.form.afterAction(this, true);
7515             return;
7516         }
7517         if(result.errors){
7518             this.form.markInvalid(result.errors);
7519             this.failureType = Roo.form.Action.SERVER_INVALID;
7520         }
7521         this.form.afterAction(this, false);
7522     },
7523     failure : function(response)
7524     {
7525         this.uploadComplete= true;
7526         if (this.haveProgress) {
7527             Roo.MessageBox.hide();
7528         }
7529         
7530         this.response = response;
7531         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7532         this.form.afterAction(this, false);
7533     },
7534     
7535     handleResponse : function(response){
7536         if(this.form.errorReader){
7537             var rs = this.form.errorReader.read(response);
7538             var errors = [];
7539             if(rs.records){
7540                 for(var i = 0, len = rs.records.length; i < len; i++) {
7541                     var r = rs.records[i];
7542                     errors[i] = r.data;
7543                 }
7544             }
7545             if(errors.length < 1){
7546                 errors = null;
7547             }
7548             return {
7549                 success : rs.success,
7550                 errors : errors
7551             };
7552         }
7553         var ret = false;
7554         try {
7555             ret = Roo.decode(response.responseText);
7556         } catch (e) {
7557             ret = {
7558                 success: false,
7559                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7560                 errors : []
7561             };
7562         }
7563         return ret;
7564         
7565     }
7566 });
7567
7568
7569 Roo.form.Action.Load = function(form, options){
7570     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7571     this.reader = this.form.reader;
7572 };
7573
7574 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7575     type : 'load',
7576
7577     run : function(){
7578         
7579         Roo.Ajax.request(Roo.apply(
7580                 this.createCallback(), {
7581                     method:this.getMethod(),
7582                     url:this.getUrl(false),
7583                     params:this.getParams()
7584         }));
7585     },
7586
7587     success : function(response){
7588         
7589         var result = this.processResponse(response);
7590         if(result === true || !result.success || !result.data){
7591             this.failureType = Roo.form.Action.LOAD_FAILURE;
7592             this.form.afterAction(this, false);
7593             return;
7594         }
7595         this.form.clearInvalid();
7596         this.form.setValues(result.data);
7597         this.form.afterAction(this, true);
7598     },
7599
7600     handleResponse : function(response){
7601         if(this.form.reader){
7602             var rs = this.form.reader.read(response);
7603             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7604             return {
7605                 success : rs.success,
7606                 data : data
7607             };
7608         }
7609         return Roo.decode(response.responseText);
7610     }
7611 });
7612
7613 Roo.form.Action.ACTION_TYPES = {
7614     'load' : Roo.form.Action.Load,
7615     'submit' : Roo.form.Action.Submit
7616 };/*
7617  * - LGPL
7618  *
7619  * form
7620  *
7621  */
7622
7623 /**
7624  * @class Roo.bootstrap.Form
7625  * @extends Roo.bootstrap.Component
7626  * Bootstrap Form class
7627  * @cfg {String} method  GET | POST (default POST)
7628  * @cfg {String} labelAlign top | left (default top)
7629  * @cfg {String} align left  | right - for navbars
7630  * @cfg {Boolean} loadMask load mask when submit (default true)
7631
7632  *
7633  * @constructor
7634  * Create a new Form
7635  * @param {Object} config The config object
7636  */
7637
7638
7639 Roo.bootstrap.Form = function(config){
7640     
7641     Roo.bootstrap.Form.superclass.constructor.call(this, config);
7642     
7643     Roo.bootstrap.Form.popover.apply();
7644     
7645     this.addEvents({
7646         /**
7647          * @event clientvalidation
7648          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7649          * @param {Form} this
7650          * @param {Boolean} valid true if the form has passed client-side validation
7651          */
7652         clientvalidation: true,
7653         /**
7654          * @event beforeaction
7655          * Fires before any action is performed. Return false to cancel the action.
7656          * @param {Form} this
7657          * @param {Action} action The action to be performed
7658          */
7659         beforeaction: true,
7660         /**
7661          * @event actionfailed
7662          * Fires when an action fails.
7663          * @param {Form} this
7664          * @param {Action} action The action that failed
7665          */
7666         actionfailed : true,
7667         /**
7668          * @event actioncomplete
7669          * Fires when an action is completed.
7670          * @param {Form} this
7671          * @param {Action} action The action that completed
7672          */
7673         actioncomplete : true
7674     });
7675 };
7676
7677 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
7678
7679      /**
7680      * @cfg {String} method
7681      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7682      */
7683     method : 'POST',
7684     /**
7685      * @cfg {String} url
7686      * The URL to use for form actions if one isn't supplied in the action options.
7687      */
7688     /**
7689      * @cfg {Boolean} fileUpload
7690      * Set to true if this form is a file upload.
7691      */
7692
7693     /**
7694      * @cfg {Object} baseParams
7695      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7696      */
7697
7698     /**
7699      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7700      */
7701     timeout: 30,
7702     /**
7703      * @cfg {Sting} align (left|right) for navbar forms
7704      */
7705     align : 'left',
7706
7707     // private
7708     activeAction : null,
7709
7710     /**
7711      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7712      * element by passing it or its id or mask the form itself by passing in true.
7713      * @type Mixed
7714      */
7715     waitMsgTarget : false,
7716
7717     loadMask : true,
7718     
7719     /**
7720      * @cfg {Boolean} errorMask (true|false) default false
7721      */
7722     errorMask : false,
7723     
7724     /**
7725      * @cfg {Number} maskOffset Default 100
7726      */
7727     maskOffset : 100,
7728     
7729     /**
7730      * @cfg {Boolean} maskBody
7731      */
7732     maskBody : false,
7733
7734     getAutoCreate : function(){
7735
7736         var cfg = {
7737             tag: 'form',
7738             method : this.method || 'POST',
7739             id : this.id || Roo.id(),
7740             cls : ''
7741         };
7742         if (this.parent().xtype.match(/^Nav/)) {
7743             cfg.cls = 'navbar-form navbar-' + this.align;
7744
7745         }
7746
7747         if (this.labelAlign == 'left' ) {
7748             cfg.cls += ' form-horizontal';
7749         }
7750
7751
7752         return cfg;
7753     },
7754     initEvents : function()
7755     {
7756         this.el.on('submit', this.onSubmit, this);
7757         // this was added as random key presses on the form where triggering form submit.
7758         this.el.on('keypress', function(e) {
7759             if (e.getCharCode() != 13) {
7760                 return true;
7761             }
7762             // we might need to allow it for textareas.. and some other items.
7763             // check e.getTarget().
7764
7765             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7766                 return true;
7767             }
7768
7769             Roo.log("keypress blocked");
7770
7771             e.preventDefault();
7772             return false;
7773         });
7774         
7775     },
7776     // private
7777     onSubmit : function(e){
7778         e.stopEvent();
7779     },
7780
7781      /**
7782      * Returns true if client-side validation on the form is successful.
7783      * @return Boolean
7784      */
7785     isValid : function(){
7786         var items = this.getItems();
7787         var valid = true;
7788         var target = false;
7789         
7790         items.each(function(f){
7791             
7792             if(f.validate()){
7793                 return;
7794             }
7795             
7796             valid = false;
7797
7798             if(!target && f.el.isVisible(true)){
7799                 target = f;
7800             }
7801            
7802         });
7803         
7804         if(this.errorMask && !valid){
7805             Roo.bootstrap.Form.popover.mask(this, target);
7806         }
7807         
7808         return valid;
7809     },
7810     
7811     /**
7812      * Returns true if any fields in this form have changed since their original load.
7813      * @return Boolean
7814      */
7815     isDirty : function(){
7816         var dirty = false;
7817         var items = this.getItems();
7818         items.each(function(f){
7819            if(f.isDirty()){
7820                dirty = true;
7821                return false;
7822            }
7823            return true;
7824         });
7825         return dirty;
7826     },
7827      /**
7828      * Performs a predefined action (submit or load) or custom actions you define on this form.
7829      * @param {String} actionName The name of the action type
7830      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
7831      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7832      * accept other config options):
7833      * <pre>
7834 Property          Type             Description
7835 ----------------  ---------------  ----------------------------------------------------------------------------------
7836 url               String           The url for the action (defaults to the form's url)
7837 method            String           The form method to use (defaults to the form's method, or POST if not defined)
7838 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
7839 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
7840                                    validate the form on the client (defaults to false)
7841      * </pre>
7842      * @return {BasicForm} this
7843      */
7844     doAction : function(action, options){
7845         if(typeof action == 'string'){
7846             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7847         }
7848         if(this.fireEvent('beforeaction', this, action) !== false){
7849             this.beforeAction(action);
7850             action.run.defer(100, action);
7851         }
7852         return this;
7853     },
7854
7855     // private
7856     beforeAction : function(action){
7857         var o = action.options;
7858         
7859         if(this.loadMask){
7860             
7861             if(this.maskBody){
7862                 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7863             } else {
7864                 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7865             }
7866         }
7867         // not really supported yet.. ??
7868
7869         //if(this.waitMsgTarget === true){
7870         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7871         //}else if(this.waitMsgTarget){
7872         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7873         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7874         //}else {
7875         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7876        // }
7877
7878     },
7879
7880     // private
7881     afterAction : function(action, success){
7882         this.activeAction = null;
7883         var o = action.options;
7884
7885         if(this.loadMask){
7886             
7887             if(this.maskBody){
7888                 Roo.get(document.body).unmask();
7889             } else {
7890                 this.el.unmask();
7891             }
7892         }
7893         
7894         //if(this.waitMsgTarget === true){
7895 //            this.el.unmask();
7896         //}else if(this.waitMsgTarget){
7897         //    this.waitMsgTarget.unmask();
7898         //}else{
7899         //    Roo.MessageBox.updateProgress(1);
7900         //    Roo.MessageBox.hide();
7901        // }
7902         //
7903         if(success){
7904             if(o.reset){
7905                 this.reset();
7906             }
7907             Roo.callback(o.success, o.scope, [this, action]);
7908             this.fireEvent('actioncomplete', this, action);
7909
7910         }else{
7911
7912             // failure condition..
7913             // we have a scenario where updates need confirming.
7914             // eg. if a locking scenario exists..
7915             // we look for { errors : { needs_confirm : true }} in the response.
7916             if (
7917                 (typeof(action.result) != 'undefined')  &&
7918                 (typeof(action.result.errors) != 'undefined')  &&
7919                 (typeof(action.result.errors.needs_confirm) != 'undefined')
7920            ){
7921                 var _t = this;
7922                 Roo.log("not supported yet");
7923                  /*
7924
7925                 Roo.MessageBox.confirm(
7926                     "Change requires confirmation",
7927                     action.result.errorMsg,
7928                     function(r) {
7929                         if (r != 'yes') {
7930                             return;
7931                         }
7932                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
7933                     }
7934
7935                 );
7936                 */
7937
7938
7939                 return;
7940             }
7941
7942             Roo.callback(o.failure, o.scope, [this, action]);
7943             // show an error message if no failed handler is set..
7944             if (!this.hasListener('actionfailed')) {
7945                 Roo.log("need to add dialog support");
7946                 /*
7947                 Roo.MessageBox.alert("Error",
7948                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7949                         action.result.errorMsg :
7950                         "Saving Failed, please check your entries or try again"
7951                 );
7952                 */
7953             }
7954
7955             this.fireEvent('actionfailed', this, action);
7956         }
7957
7958     },
7959     /**
7960      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7961      * @param {String} id The value to search for
7962      * @return Field
7963      */
7964     findField : function(id){
7965         var items = this.getItems();
7966         var field = items.get(id);
7967         if(!field){
7968              items.each(function(f){
7969                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7970                     field = f;
7971                     return false;
7972                 }
7973                 return true;
7974             });
7975         }
7976         return field || null;
7977     },
7978      /**
7979      * Mark fields in this form invalid in bulk.
7980      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7981      * @return {BasicForm} this
7982      */
7983     markInvalid : function(errors){
7984         if(errors instanceof Array){
7985             for(var i = 0, len = errors.length; i < len; i++){
7986                 var fieldError = errors[i];
7987                 var f = this.findField(fieldError.id);
7988                 if(f){
7989                     f.markInvalid(fieldError.msg);
7990                 }
7991             }
7992         }else{
7993             var field, id;
7994             for(id in errors){
7995                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7996                     field.markInvalid(errors[id]);
7997                 }
7998             }
7999         }
8000         //Roo.each(this.childForms || [], function (f) {
8001         //    f.markInvalid(errors);
8002         //});
8003
8004         return this;
8005     },
8006
8007     /**
8008      * Set values for fields in this form in bulk.
8009      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8010      * @return {BasicForm} this
8011      */
8012     setValues : function(values){
8013         if(values instanceof Array){ // array of objects
8014             for(var i = 0, len = values.length; i < len; i++){
8015                 var v = values[i];
8016                 var f = this.findField(v.id);
8017                 if(f){
8018                     f.setValue(v.value);
8019                     if(this.trackResetOnLoad){
8020                         f.originalValue = f.getValue();
8021                     }
8022                 }
8023             }
8024         }else{ // object hash
8025             var field, id;
8026             for(id in values){
8027                 if(typeof values[id] != 'function' && (field = this.findField(id))){
8028
8029                     if (field.setFromData &&
8030                         field.valueField &&
8031                         field.displayField &&
8032                         // combos' with local stores can
8033                         // be queried via setValue()
8034                         // to set their value..
8035                         (field.store && !field.store.isLocal)
8036                         ) {
8037                         // it's a combo
8038                         var sd = { };
8039                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8040                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8041                         field.setFromData(sd);
8042
8043                     } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8044                         
8045                         field.setFromData(values);
8046                         
8047                     } else {
8048                         field.setValue(values[id]);
8049                     }
8050
8051
8052                     if(this.trackResetOnLoad){
8053                         field.originalValue = field.getValue();
8054                     }
8055                 }
8056             }
8057         }
8058
8059         //Roo.each(this.childForms || [], function (f) {
8060         //    f.setValues(values);
8061         //});
8062
8063         return this;
8064     },
8065
8066     /**
8067      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8068      * they are returned as an array.
8069      * @param {Boolean} asString
8070      * @return {Object}
8071      */
8072     getValues : function(asString){
8073         //if (this.childForms) {
8074             // copy values from the child forms
8075         //    Roo.each(this.childForms, function (f) {
8076         //        this.setValues(f.getValues());
8077         //    }, this);
8078         //}
8079
8080
8081
8082         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8083         if(asString === true){
8084             return fs;
8085         }
8086         return Roo.urlDecode(fs);
8087     },
8088
8089     /**
8090      * Returns the fields in this form as an object with key/value pairs.
8091      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8092      * @return {Object}
8093      */
8094     getFieldValues : function(with_hidden)
8095     {
8096         var items = this.getItems();
8097         var ret = {};
8098         items.each(function(f){
8099             
8100             if (!f.getName()) {
8101                 return;
8102             }
8103             
8104             var v = f.getValue();
8105             
8106             if (f.inputType =='radio') {
8107                 if (typeof(ret[f.getName()]) == 'undefined') {
8108                     ret[f.getName()] = ''; // empty..
8109                 }
8110
8111                 if (!f.el.dom.checked) {
8112                     return;
8113
8114                 }
8115                 v = f.el.dom.value;
8116
8117             }
8118             
8119             if(f.xtype == 'MoneyField'){
8120                 ret[f.currencyName] = f.getCurrency();
8121             }
8122
8123             // not sure if this supported any more..
8124             if ((typeof(v) == 'object') && f.getRawValue) {
8125                 v = f.getRawValue() ; // dates..
8126             }
8127             // combo boxes where name != hiddenName...
8128             if (f.name !== false && f.name != '' && f.name != f.getName()) {
8129                 ret[f.name] = f.getRawValue();
8130             }
8131             ret[f.getName()] = v;
8132         });
8133
8134         return ret;
8135     },
8136
8137     /**
8138      * Clears all invalid messages in this form.
8139      * @return {BasicForm} this
8140      */
8141     clearInvalid : function(){
8142         var items = this.getItems();
8143
8144         items.each(function(f){
8145            f.clearInvalid();
8146         });
8147
8148         return this;
8149     },
8150
8151     /**
8152      * Resets this form.
8153      * @return {BasicForm} this
8154      */
8155     reset : function(){
8156         var items = this.getItems();
8157         items.each(function(f){
8158             f.reset();
8159         });
8160
8161         Roo.each(this.childForms || [], function (f) {
8162             f.reset();
8163         });
8164
8165
8166         return this;
8167     },
8168     
8169     getItems : function()
8170     {
8171         var r=new Roo.util.MixedCollection(false, function(o){
8172             return o.id || (o.id = Roo.id());
8173         });
8174         var iter = function(el) {
8175             if (el.inputEl) {
8176                 r.add(el);
8177             }
8178             if (!el.items) {
8179                 return;
8180             }
8181             Roo.each(el.items,function(e) {
8182                 iter(e);
8183             });
8184         };
8185
8186         iter(this);
8187         return r;
8188     },
8189     
8190     hideFields : function(items)
8191     {
8192         Roo.each(items, function(i){
8193             
8194             var f = this.findField(i);
8195             
8196             if(!f){
8197                 return;
8198             }
8199             
8200             if(f.xtype == 'DateField'){
8201                 f.setVisible(false);
8202                 return;
8203             }
8204             
8205             f.hide();
8206             
8207         }, this);
8208     },
8209     
8210     showFields : function(items)
8211     {
8212         Roo.each(items, function(i){
8213             
8214             var f = this.findField(i);
8215             
8216             if(!f){
8217                 return;
8218             }
8219             
8220             if(f.xtype == 'DateField'){
8221                 f.setVisible(true);
8222                 return;
8223             }
8224             
8225             f.show();
8226             
8227         }, this);
8228     }
8229
8230 });
8231
8232 Roo.apply(Roo.bootstrap.Form, {
8233     
8234     popover : {
8235         
8236         padding : 5,
8237         
8238         isApplied : false,
8239         
8240         isMasked : false,
8241         
8242         form : false,
8243         
8244         target : false,
8245         
8246         toolTip : false,
8247         
8248         intervalID : false,
8249         
8250         maskEl : false,
8251         
8252         apply : function()
8253         {
8254             if(this.isApplied){
8255                 return;
8256             }
8257             
8258             this.maskEl = {
8259                 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8260                 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8261                 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8262                 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8263             };
8264             
8265             this.maskEl.top.enableDisplayMode("block");
8266             this.maskEl.left.enableDisplayMode("block");
8267             this.maskEl.bottom.enableDisplayMode("block");
8268             this.maskEl.right.enableDisplayMode("block");
8269             
8270             this.toolTip = new Roo.bootstrap.Tooltip({
8271                 cls : 'roo-form-error-popover',
8272                 alignment : {
8273                     'left' : ['r-l', [-2,0], 'right'],
8274                     'right' : ['l-r', [2,0], 'left'],
8275                     'bottom' : ['tl-bl', [0,2], 'top'],
8276                     'top' : [ 'bl-tl', [0,-2], 'bottom']
8277                 }
8278             });
8279             
8280             this.toolTip.render(Roo.get(document.body));
8281
8282             this.toolTip.el.enableDisplayMode("block");
8283             
8284             Roo.get(document.body).on('click', function(){
8285                 this.unmask();
8286             }, this);
8287             
8288             Roo.get(document.body).on('touchstart', function(){
8289                 this.unmask();
8290             }, this);
8291             
8292             this.isApplied = true
8293         },
8294         
8295         mask : function(form, target)
8296         {
8297             this.form = form;
8298             
8299             this.target = target;
8300             
8301             if(!this.form.errorMask || !target.el){
8302                 return;
8303             }
8304             
8305             var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8306             
8307             Roo.log(scrollable);
8308             
8309             var ot = this.target.el.calcOffsetsTo(scrollable);
8310             
8311             var scrollTo = ot[1] - this.form.maskOffset;
8312             
8313             scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8314             
8315             scrollable.scrollTo('top', scrollTo);
8316             
8317             var box = this.target.el.getBox();
8318             Roo.log(box);
8319             var zIndex = Roo.bootstrap.Modal.zIndex++;
8320
8321             
8322             this.maskEl.top.setStyle('position', 'absolute');
8323             this.maskEl.top.setStyle('z-index', zIndex);
8324             this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8325             this.maskEl.top.setLeft(0);
8326             this.maskEl.top.setTop(0);
8327             this.maskEl.top.show();
8328             
8329             this.maskEl.left.setStyle('position', 'absolute');
8330             this.maskEl.left.setStyle('z-index', zIndex);
8331             this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8332             this.maskEl.left.setLeft(0);
8333             this.maskEl.left.setTop(box.y - this.padding);
8334             this.maskEl.left.show();
8335
8336             this.maskEl.bottom.setStyle('position', 'absolute');
8337             this.maskEl.bottom.setStyle('z-index', zIndex);
8338             this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8339             this.maskEl.bottom.setLeft(0);
8340             this.maskEl.bottom.setTop(box.bottom + this.padding);
8341             this.maskEl.bottom.show();
8342
8343             this.maskEl.right.setStyle('position', 'absolute');
8344             this.maskEl.right.setStyle('z-index', zIndex);
8345             this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8346             this.maskEl.right.setLeft(box.right + this.padding);
8347             this.maskEl.right.setTop(box.y - this.padding);
8348             this.maskEl.right.show();
8349
8350             this.toolTip.bindEl = this.target.el;
8351
8352             this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8353
8354             var tip = this.target.blankText;
8355
8356             if(this.target.getValue() !== '' ) {
8357                 
8358                 if (this.target.invalidText.length) {
8359                     tip = this.target.invalidText;
8360                 } else if (this.target.regexText.length){
8361                     tip = this.target.regexText;
8362                 }
8363             }
8364
8365             this.toolTip.show(tip);
8366
8367             this.intervalID = window.setInterval(function() {
8368                 Roo.bootstrap.Form.popover.unmask();
8369             }, 10000);
8370
8371             window.onwheel = function(){ return false;};
8372             
8373             (function(){ this.isMasked = true; }).defer(500, this);
8374             
8375         },
8376         
8377         unmask : function()
8378         {
8379             if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8380                 return;
8381             }
8382             
8383             this.maskEl.top.setStyle('position', 'absolute');
8384             this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8385             this.maskEl.top.hide();
8386
8387             this.maskEl.left.setStyle('position', 'absolute');
8388             this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8389             this.maskEl.left.hide();
8390
8391             this.maskEl.bottom.setStyle('position', 'absolute');
8392             this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8393             this.maskEl.bottom.hide();
8394
8395             this.maskEl.right.setStyle('position', 'absolute');
8396             this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8397             this.maskEl.right.hide();
8398             
8399             this.toolTip.hide();
8400             
8401             this.toolTip.el.hide();
8402             
8403             window.onwheel = function(){ return true;};
8404             
8405             if(this.intervalID){
8406                 window.clearInterval(this.intervalID);
8407                 this.intervalID = false;
8408             }
8409             
8410             this.isMasked = false;
8411             
8412         }
8413         
8414     }
8415     
8416 });
8417
8418 /*
8419  * Based on:
8420  * Ext JS Library 1.1.1
8421  * Copyright(c) 2006-2007, Ext JS, LLC.
8422  *
8423  * Originally Released Under LGPL - original licence link has changed is not relivant.
8424  *
8425  * Fork - LGPL
8426  * <script type="text/javascript">
8427  */
8428 /**
8429  * @class Roo.form.VTypes
8430  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8431  * @singleton
8432  */
8433 Roo.form.VTypes = function(){
8434     // closure these in so they are only created once.
8435     var alpha = /^[a-zA-Z_]+$/;
8436     var alphanum = /^[a-zA-Z0-9_]+$/;
8437     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8438     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8439
8440     // All these messages and functions are configurable
8441     return {
8442         /**
8443          * The function used to validate email addresses
8444          * @param {String} value The email address
8445          */
8446         'email' : function(v){
8447             return email.test(v);
8448         },
8449         /**
8450          * The error text to display when the email validation function returns false
8451          * @type String
8452          */
8453         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8454         /**
8455          * The keystroke filter mask to be applied on email input
8456          * @type RegExp
8457          */
8458         'emailMask' : /[a-z0-9_\.\-@]/i,
8459
8460         /**
8461          * The function used to validate URLs
8462          * @param {String} value The URL
8463          */
8464         'url' : function(v){
8465             return url.test(v);
8466         },
8467         /**
8468          * The error text to display when the url validation function returns false
8469          * @type String
8470          */
8471         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8472         
8473         /**
8474          * The function used to validate alpha values
8475          * @param {String} value The value
8476          */
8477         'alpha' : function(v){
8478             return alpha.test(v);
8479         },
8480         /**
8481          * The error text to display when the alpha validation function returns false
8482          * @type String
8483          */
8484         'alphaText' : 'This field should only contain letters and _',
8485         /**
8486          * The keystroke filter mask to be applied on alpha input
8487          * @type RegExp
8488          */
8489         'alphaMask' : /[a-z_]/i,
8490
8491         /**
8492          * The function used to validate alphanumeric values
8493          * @param {String} value The value
8494          */
8495         'alphanum' : function(v){
8496             return alphanum.test(v);
8497         },
8498         /**
8499          * The error text to display when the alphanumeric validation function returns false
8500          * @type String
8501          */
8502         'alphanumText' : 'This field should only contain letters, numbers and _',
8503         /**
8504          * The keystroke filter mask to be applied on alphanumeric input
8505          * @type RegExp
8506          */
8507         'alphanumMask' : /[a-z0-9_]/i
8508     };
8509 }();/*
8510  * - LGPL
8511  *
8512  * Input
8513  * 
8514  */
8515
8516 /**
8517  * @class Roo.bootstrap.Input
8518  * @extends Roo.bootstrap.Component
8519  * Bootstrap Input class
8520  * @cfg {Boolean} disabled is it disabled
8521  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8522  * @cfg {String} name name of the input
8523  * @cfg {string} fieldLabel - the label associated
8524  * @cfg {string} placeholder - placeholder to put in text.
8525  * @cfg {string}  before - input group add on before
8526  * @cfg {string} after - input group add on after
8527  * @cfg {string} size - (lg|sm) or leave empty..
8528  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8529  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8530  * @cfg {Number} md colspan out of 12 for computer-sized screens
8531  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8532  * @cfg {string} value default value of the input
8533  * @cfg {Number} labelWidth set the width of label 
8534  * @cfg {Number} labellg set the width of label (1-12)
8535  * @cfg {Number} labelmd set the width of label (1-12)
8536  * @cfg {Number} labelsm set the width of label (1-12)
8537  * @cfg {Number} labelxs set the width of label (1-12)
8538  * @cfg {String} labelAlign (top|left)
8539  * @cfg {Boolean} readOnly Specifies that the field should be read-only
8540  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8541  * @cfg {String} indicatorpos (left|right) default left
8542  * @cfg {String} capture (user|camera) use for file input only. (default empty)
8543  * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8544
8545  * @cfg {String} align (left|center|right) Default left
8546  * @cfg {Boolean} forceFeedback (true|false) Default false
8547  * 
8548  * @constructor
8549  * Create a new Input
8550  * @param {Object} config The config object
8551  */
8552
8553 Roo.bootstrap.Input = function(config){
8554     
8555     Roo.bootstrap.Input.superclass.constructor.call(this, config);
8556     
8557     this.addEvents({
8558         /**
8559          * @event focus
8560          * Fires when this field receives input focus.
8561          * @param {Roo.form.Field} this
8562          */
8563         focus : true,
8564         /**
8565          * @event blur
8566          * Fires when this field loses input focus.
8567          * @param {Roo.form.Field} this
8568          */
8569         blur : true,
8570         /**
8571          * @event specialkey
8572          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
8573          * {@link Roo.EventObject#getKey} to determine which key was pressed.
8574          * @param {Roo.form.Field} this
8575          * @param {Roo.EventObject} e The event object
8576          */
8577         specialkey : true,
8578         /**
8579          * @event change
8580          * Fires just before the field blurs if the field value has changed.
8581          * @param {Roo.form.Field} this
8582          * @param {Mixed} newValue The new value
8583          * @param {Mixed} oldValue The original value
8584          */
8585         change : true,
8586         /**
8587          * @event invalid
8588          * Fires after the field has been marked as invalid.
8589          * @param {Roo.form.Field} this
8590          * @param {String} msg The validation message
8591          */
8592         invalid : true,
8593         /**
8594          * @event valid
8595          * Fires after the field has been validated with no errors.
8596          * @param {Roo.form.Field} this
8597          */
8598         valid : true,
8599          /**
8600          * @event keyup
8601          * Fires after the key up
8602          * @param {Roo.form.Field} this
8603          * @param {Roo.EventObject}  e The event Object
8604          */
8605         keyup : true
8606     });
8607 };
8608
8609 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
8610      /**
8611      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8612       automatic validation (defaults to "keyup").
8613      */
8614     validationEvent : "keyup",
8615      /**
8616      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8617      */
8618     validateOnBlur : true,
8619     /**
8620      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8621      */
8622     validationDelay : 250,
8623      /**
8624      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8625      */
8626     focusClass : "x-form-focus",  // not needed???
8627     
8628        
8629     /**
8630      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8631      */
8632     invalidClass : "has-warning",
8633     
8634     /**
8635      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8636      */
8637     validClass : "has-success",
8638     
8639     /**
8640      * @cfg {Boolean} hasFeedback (true|false) default true
8641      */
8642     hasFeedback : true,
8643     
8644     /**
8645      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8646      */
8647     invalidFeedbackClass : "glyphicon-warning-sign",
8648     
8649     /**
8650      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8651      */
8652     validFeedbackClass : "glyphicon-ok",
8653     
8654     /**
8655      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8656      */
8657     selectOnFocus : false,
8658     
8659      /**
8660      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8661      */
8662     maskRe : null,
8663        /**
8664      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8665      */
8666     vtype : null,
8667     
8668       /**
8669      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8670      */
8671     disableKeyFilter : false,
8672     
8673        /**
8674      * @cfg {Boolean} disabled True to disable the field (defaults to false).
8675      */
8676     disabled : false,
8677      /**
8678      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8679      */
8680     allowBlank : true,
8681     /**
8682      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8683      */
8684     blankText : "Please complete this mandatory field",
8685     
8686      /**
8687      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8688      */
8689     minLength : 0,
8690     /**
8691      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8692      */
8693     maxLength : Number.MAX_VALUE,
8694     /**
8695      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8696      */
8697     minLengthText : "The minimum length for this field is {0}",
8698     /**
8699      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8700      */
8701     maxLengthText : "The maximum length for this field is {0}",
8702   
8703     
8704     /**
8705      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8706      * If available, this function will be called only after the basic validators all return true, and will be passed the
8707      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8708      */
8709     validator : null,
8710     /**
8711      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8712      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8713      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
8714      */
8715     regex : null,
8716     /**
8717      * @cfg {String} regexText -- Depricated - use Invalid Text
8718      */
8719     regexText : "",
8720     
8721     /**
8722      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8723      */
8724     invalidText : "",
8725     
8726     
8727     
8728     autocomplete: false,
8729     
8730     
8731     fieldLabel : '',
8732     inputType : 'text',
8733     
8734     name : false,
8735     placeholder: false,
8736     before : false,
8737     after : false,
8738     size : false,
8739     hasFocus : false,
8740     preventMark: false,
8741     isFormField : true,
8742     value : '',
8743     labelWidth : 2,
8744     labelAlign : false,
8745     readOnly : false,
8746     align : false,
8747     formatedValue : false,
8748     forceFeedback : false,
8749     
8750     indicatorpos : 'left',
8751     
8752     labellg : 0,
8753     labelmd : 0,
8754     labelsm : 0,
8755     labelxs : 0,
8756     
8757     capture : '',
8758     accept : '',
8759     
8760     parentLabelAlign : function()
8761     {
8762         var parent = this;
8763         while (parent.parent()) {
8764             parent = parent.parent();
8765             if (typeof(parent.labelAlign) !='undefined') {
8766                 return parent.labelAlign;
8767             }
8768         }
8769         return 'left';
8770         
8771     },
8772     
8773     getAutoCreate : function()
8774     {
8775         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8776         
8777         var id = Roo.id();
8778         
8779         var cfg = {};
8780         
8781         if(this.inputType != 'hidden'){
8782             cfg.cls = 'form-group' //input-group
8783         }
8784         
8785         var input =  {
8786             tag: 'input',
8787             id : id,
8788             type : this.inputType,
8789             value : this.value,
8790             cls : 'form-control',
8791             placeholder : this.placeholder || '',
8792             autocomplete : this.autocomplete || 'new-password'
8793         };
8794         
8795         if(this.capture.length){
8796             input.capture = this.capture;
8797         }
8798         
8799         if(this.accept.length){
8800             input.accept = this.accept + "/*";
8801         }
8802         
8803         if(this.align){
8804             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8805         }
8806         
8807         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8808             input.maxLength = this.maxLength;
8809         }
8810         
8811         if (this.disabled) {
8812             input.disabled=true;
8813         }
8814         
8815         if (this.readOnly) {
8816             input.readonly=true;
8817         }
8818         
8819         if (this.name) {
8820             input.name = this.name;
8821         }
8822         
8823         if (this.size) {
8824             input.cls += ' input-' + this.size;
8825         }
8826         
8827         var settings=this;
8828         ['xs','sm','md','lg'].map(function(size){
8829             if (settings[size]) {
8830                 cfg.cls += ' col-' + size + '-' + settings[size];
8831             }
8832         });
8833         
8834         var inputblock = input;
8835         
8836         var feedback = {
8837             tag: 'span',
8838             cls: 'glyphicon form-control-feedback'
8839         };
8840             
8841         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8842             
8843             inputblock = {
8844                 cls : 'has-feedback',
8845                 cn :  [
8846                     input,
8847                     feedback
8848                 ] 
8849             };  
8850         }
8851         
8852         if (this.before || this.after) {
8853             
8854             inputblock = {
8855                 cls : 'input-group',
8856                 cn :  [] 
8857             };
8858             
8859             if (this.before && typeof(this.before) == 'string') {
8860                 
8861                 inputblock.cn.push({
8862                     tag :'span',
8863                     cls : 'roo-input-before input-group-addon',
8864                     html : this.before
8865                 });
8866             }
8867             if (this.before && typeof(this.before) == 'object') {
8868                 this.before = Roo.factory(this.before);
8869                 
8870                 inputblock.cn.push({
8871                     tag :'span',
8872                     cls : 'roo-input-before input-group-' +
8873                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8874                 });
8875             }
8876             
8877             inputblock.cn.push(input);
8878             
8879             if (this.after && typeof(this.after) == 'string') {
8880                 inputblock.cn.push({
8881                     tag :'span',
8882                     cls : 'roo-input-after input-group-addon',
8883                     html : this.after
8884                 });
8885             }
8886             if (this.after && typeof(this.after) == 'object') {
8887                 this.after = Roo.factory(this.after);
8888                 
8889                 inputblock.cn.push({
8890                     tag :'span',
8891                     cls : 'roo-input-after input-group-' +
8892                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8893                 });
8894             }
8895             
8896             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8897                 inputblock.cls += ' has-feedback';
8898                 inputblock.cn.push(feedback);
8899             }
8900         };
8901         
8902         if (align ==='left' && this.fieldLabel.length) {
8903             
8904             cfg.cls += ' roo-form-group-label-left';
8905             
8906             cfg.cn = [
8907                 {
8908                     tag : 'i',
8909                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8910                     tooltip : 'This field is required'
8911                 },
8912                 {
8913                     tag: 'label',
8914                     'for' :  id,
8915                     cls : 'control-label',
8916                     html : this.fieldLabel
8917
8918                 },
8919                 {
8920                     cls : "", 
8921                     cn: [
8922                         inputblock
8923                     ]
8924                 }
8925             ];
8926             
8927             var labelCfg = cfg.cn[1];
8928             var contentCfg = cfg.cn[2];
8929             
8930             if(this.indicatorpos == 'right'){
8931                 cfg.cn = [
8932                     {
8933                         tag: 'label',
8934                         'for' :  id,
8935                         cls : 'control-label',
8936                         cn : [
8937                             {
8938                                 tag : 'span',
8939                                 html : this.fieldLabel
8940                             },
8941                             {
8942                                 tag : 'i',
8943                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8944                                 tooltip : 'This field is required'
8945                             }
8946                         ]
8947                     },
8948                     {
8949                         cls : "",
8950                         cn: [
8951                             inputblock
8952                         ]
8953                     }
8954
8955                 ];
8956                 
8957                 labelCfg = cfg.cn[0];
8958                 contentCfg = cfg.cn[1];
8959             
8960             }
8961             
8962             if(this.labelWidth > 12){
8963                 labelCfg.style = "width: " + this.labelWidth + 'px';
8964             }
8965             
8966             if(this.labelWidth < 13 && this.labelmd == 0){
8967                 this.labelmd = this.labelWidth;
8968             }
8969             
8970             if(this.labellg > 0){
8971                 labelCfg.cls += ' col-lg-' + this.labellg;
8972                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8973             }
8974             
8975             if(this.labelmd > 0){
8976                 labelCfg.cls += ' col-md-' + this.labelmd;
8977                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8978             }
8979             
8980             if(this.labelsm > 0){
8981                 labelCfg.cls += ' col-sm-' + this.labelsm;
8982                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8983             }
8984             
8985             if(this.labelxs > 0){
8986                 labelCfg.cls += ' col-xs-' + this.labelxs;
8987                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8988             }
8989             
8990             
8991         } else if ( this.fieldLabel.length) {
8992                 
8993             cfg.cn = [
8994                 {
8995                     tag : 'i',
8996                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8997                     tooltip : 'This field is required'
8998                 },
8999                 {
9000                     tag: 'label',
9001                    //cls : 'input-group-addon',
9002                     html : this.fieldLabel
9003
9004                 },
9005
9006                inputblock
9007
9008            ];
9009            
9010            if(this.indicatorpos == 'right'){
9011                 
9012                 cfg.cn = [
9013                     {
9014                         tag: 'label',
9015                        //cls : 'input-group-addon',
9016                         html : this.fieldLabel
9017
9018                     },
9019                     {
9020                         tag : 'i',
9021                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9022                         tooltip : 'This field is required'
9023                     },
9024
9025                    inputblock
9026
9027                ];
9028
9029             }
9030
9031         } else {
9032             
9033             cfg.cn = [
9034
9035                     inputblock
9036
9037             ];
9038                 
9039                 
9040         };
9041         
9042         if (this.parentType === 'Navbar' &&  this.parent().bar) {
9043            cfg.cls += ' navbar-form';
9044         }
9045         
9046         if (this.parentType === 'NavGroup') {
9047            cfg.cls += ' navbar-form';
9048            cfg.tag = 'li';
9049         }
9050         
9051         return cfg;
9052         
9053     },
9054     /**
9055      * return the real input element.
9056      */
9057     inputEl: function ()
9058     {
9059         return this.el.select('input.form-control',true).first();
9060     },
9061     
9062     tooltipEl : function()
9063     {
9064         return this.inputEl();
9065     },
9066     
9067     indicatorEl : function()
9068     {
9069         var indicator = this.el.select('i.roo-required-indicator',true).first();
9070         
9071         if(!indicator){
9072             return false;
9073         }
9074         
9075         return indicator;
9076         
9077     },
9078     
9079     setDisabled : function(v)
9080     {
9081         var i  = this.inputEl().dom;
9082         if (!v) {
9083             i.removeAttribute('disabled');
9084             return;
9085             
9086         }
9087         i.setAttribute('disabled','true');
9088     },
9089     initEvents : function()
9090     {
9091           
9092         this.inputEl().on("keydown" , this.fireKey,  this);
9093         this.inputEl().on("focus", this.onFocus,  this);
9094         this.inputEl().on("blur", this.onBlur,  this);
9095         
9096         this.inputEl().relayEvent('keyup', this);
9097         
9098         this.indicator = this.indicatorEl();
9099         
9100         if(this.indicator){
9101             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? - 
9102         }
9103  
9104         // reference to original value for reset
9105         this.originalValue = this.getValue();
9106         //Roo.form.TextField.superclass.initEvents.call(this);
9107         if(this.validationEvent == 'keyup'){
9108             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9109             this.inputEl().on('keyup', this.filterValidation, this);
9110         }
9111         else if(this.validationEvent !== false){
9112             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9113         }
9114         
9115         if(this.selectOnFocus){
9116             this.on("focus", this.preFocus, this);
9117             
9118         }
9119         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9120             this.inputEl().on("keypress", this.filterKeys, this);
9121         } else {
9122             this.inputEl().relayEvent('keypress', this);
9123         }
9124        /* if(this.grow){
9125             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
9126             this.el.on("click", this.autoSize,  this);
9127         }
9128         */
9129         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9130             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9131         }
9132         
9133         if (typeof(this.before) == 'object') {
9134             this.before.render(this.el.select('.roo-input-before',true).first());
9135         }
9136         if (typeof(this.after) == 'object') {
9137             this.after.render(this.el.select('.roo-input-after',true).first());
9138         }
9139         
9140         this.inputEl().on('change', this.onChange, this);
9141         
9142     },
9143     filterValidation : function(e){
9144         if(!e.isNavKeyPress()){
9145             this.validationTask.delay(this.validationDelay);
9146         }
9147     },
9148      /**
9149      * Validates the field value
9150      * @return {Boolean} True if the value is valid, else false
9151      */
9152     validate : function(){
9153         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9154         if(this.disabled || this.validateValue(this.getRawValue())){
9155             this.markValid();
9156             return true;
9157         }
9158         
9159         this.markInvalid();
9160         return false;
9161     },
9162     
9163     
9164     /**
9165      * Validates a value according to the field's validation rules and marks the field as invalid
9166      * if the validation fails
9167      * @param {Mixed} value The value to validate
9168      * @return {Boolean} True if the value is valid, else false
9169      */
9170     validateValue : function(value)
9171     {
9172         if(this.getVisibilityEl().hasClass('hidden')){
9173             return true;
9174         }
9175         
9176         if(value.length < 1)  { // if it's blank
9177             if(this.allowBlank){
9178                 return true;
9179             }
9180             return false;
9181         }
9182         
9183         if(value.length < this.minLength){
9184             return false;
9185         }
9186         if(value.length > this.maxLength){
9187             return false;
9188         }
9189         if(this.vtype){
9190             var vt = Roo.form.VTypes;
9191             if(!vt[this.vtype](value, this)){
9192                 return false;
9193             }
9194         }
9195         if(typeof this.validator == "function"){
9196             var msg = this.validator(value);
9197             if(msg !== true){
9198                 return false;
9199             }
9200             if (typeof(msg) == 'string') {
9201                 this.invalidText = msg;
9202             }
9203         }
9204         
9205         if(this.regex && !this.regex.test(value)){
9206             return false;
9207         }
9208         
9209         return true;
9210     },
9211     
9212      // private
9213     fireKey : function(e){
9214         //Roo.log('field ' + e.getKey());
9215         if(e.isNavKeyPress()){
9216             this.fireEvent("specialkey", this, e);
9217         }
9218     },
9219     focus : function (selectText){
9220         if(this.rendered){
9221             this.inputEl().focus();
9222             if(selectText === true){
9223                 this.inputEl().dom.select();
9224             }
9225         }
9226         return this;
9227     } ,
9228     
9229     onFocus : function(){
9230         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9231            // this.el.addClass(this.focusClass);
9232         }
9233         if(!this.hasFocus){
9234             this.hasFocus = true;
9235             this.startValue = this.getValue();
9236             this.fireEvent("focus", this);
9237         }
9238     },
9239     
9240     beforeBlur : Roo.emptyFn,
9241
9242     
9243     // private
9244     onBlur : function(){
9245         this.beforeBlur();
9246         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9247             //this.el.removeClass(this.focusClass);
9248         }
9249         this.hasFocus = false;
9250         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9251             this.validate();
9252         }
9253         var v = this.getValue();
9254         if(String(v) !== String(this.startValue)){
9255             this.fireEvent('change', this, v, this.startValue);
9256         }
9257         this.fireEvent("blur", this);
9258     },
9259     
9260     onChange : function(e)
9261     {
9262         var v = this.getValue();
9263         if(String(v) !== String(this.startValue)){
9264             this.fireEvent('change', this, v, this.startValue);
9265         }
9266         
9267     },
9268     
9269     /**
9270      * Resets the current field value to the originally loaded value and clears any validation messages
9271      */
9272     reset : function(){
9273         this.setValue(this.originalValue);
9274         this.validate();
9275     },
9276      /**
9277      * Returns the name of the field
9278      * @return {Mixed} name The name field
9279      */
9280     getName: function(){
9281         return this.name;
9282     },
9283      /**
9284      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
9285      * @return {Mixed} value The field value
9286      */
9287     getValue : function(){
9288         
9289         var v = this.inputEl().getValue();
9290         
9291         return v;
9292     },
9293     /**
9294      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
9295      * @return {Mixed} value The field value
9296      */
9297     getRawValue : function(){
9298         var v = this.inputEl().getValue();
9299         
9300         return v;
9301     },
9302     
9303     /**
9304      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
9305      * @param {Mixed} value The value to set
9306      */
9307     setRawValue : function(v){
9308         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9309     },
9310     
9311     selectText : function(start, end){
9312         var v = this.getRawValue();
9313         if(v.length > 0){
9314             start = start === undefined ? 0 : start;
9315             end = end === undefined ? v.length : end;
9316             var d = this.inputEl().dom;
9317             if(d.setSelectionRange){
9318                 d.setSelectionRange(start, end);
9319             }else if(d.createTextRange){
9320                 var range = d.createTextRange();
9321                 range.moveStart("character", start);
9322                 range.moveEnd("character", v.length-end);
9323                 range.select();
9324             }
9325         }
9326     },
9327     
9328     /**
9329      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
9330      * @param {Mixed} value The value to set
9331      */
9332     setValue : function(v){
9333         this.value = v;
9334         if(this.rendered){
9335             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9336             this.validate();
9337         }
9338     },
9339     
9340     /*
9341     processValue : function(value){
9342         if(this.stripCharsRe){
9343             var newValue = value.replace(this.stripCharsRe, '');
9344             if(newValue !== value){
9345                 this.setRawValue(newValue);
9346                 return newValue;
9347             }
9348         }
9349         return value;
9350     },
9351   */
9352     preFocus : function(){
9353         
9354         if(this.selectOnFocus){
9355             this.inputEl().dom.select();
9356         }
9357     },
9358     filterKeys : function(e){
9359         var k = e.getKey();
9360         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9361             return;
9362         }
9363         var c = e.getCharCode(), cc = String.fromCharCode(c);
9364         if(Roo.isIE && (e.isSpecialKey() || !cc)){
9365             return;
9366         }
9367         if(!this.maskRe.test(cc)){
9368             e.stopEvent();
9369         }
9370     },
9371      /**
9372      * Clear any invalid styles/messages for this field
9373      */
9374     clearInvalid : function(){
9375         
9376         if(!this.el || this.preventMark){ // not rendered
9377             return;
9378         }
9379         
9380      
9381         this.el.removeClass(this.invalidClass);
9382         
9383         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9384             
9385             var feedback = this.el.select('.form-control-feedback', true).first();
9386             
9387             if(feedback){
9388                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9389             }
9390             
9391         }
9392         
9393         this.fireEvent('valid', this);
9394     },
9395     
9396      /**
9397      * Mark this field as valid
9398      */
9399     markValid : function()
9400     {
9401         if(!this.el  || this.preventMark){ // not rendered...
9402             return;
9403         }
9404         
9405         this.el.removeClass([this.invalidClass, this.validClass]);
9406         
9407         var feedback = this.el.select('.form-control-feedback', true).first();
9408             
9409         if(feedback){
9410             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9411         }
9412         
9413         if(this.indicator){
9414             this.indicator.removeClass('visible');
9415             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9416         }
9417         
9418         if(this.disabled){
9419             return;
9420         }
9421         
9422         if(this.allowBlank && !this.getRawValue().length){
9423             return;
9424         }
9425         
9426         this.el.addClass(this.validClass);
9427         
9428         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9429             
9430             var feedback = this.el.select('.form-control-feedback', true).first();
9431             
9432             if(feedback){
9433                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9434                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9435             }
9436             
9437         }
9438         
9439         this.fireEvent('valid', this);
9440     },
9441     
9442      /**
9443      * Mark this field as invalid
9444      * @param {String} msg The validation message
9445      */
9446     markInvalid : function(msg)
9447     {
9448         if(!this.el  || this.preventMark){ // not rendered
9449             return;
9450         }
9451         
9452         this.el.removeClass([this.invalidClass, this.validClass]);
9453         
9454         var feedback = this.el.select('.form-control-feedback', true).first();
9455             
9456         if(feedback){
9457             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9458         }
9459
9460         if(this.disabled){
9461             return;
9462         }
9463         
9464         if(this.allowBlank && !this.getRawValue().length){
9465             return;
9466         }
9467         
9468         if(this.indicator){
9469             this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9470             this.indicator.addClass('visible');
9471         }
9472         
9473         this.el.addClass(this.invalidClass);
9474         
9475         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9476             
9477             var feedback = this.el.select('.form-control-feedback', true).first();
9478             
9479             if(feedback){
9480                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9481                 
9482                 if(this.getValue().length || this.forceFeedback){
9483                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9484                 }
9485                 
9486             }
9487             
9488         }
9489         
9490         this.fireEvent('invalid', this, msg);
9491     },
9492     // private
9493     SafariOnKeyDown : function(event)
9494     {
9495         // this is a workaround for a password hang bug on chrome/ webkit.
9496         if (this.inputEl().dom.type != 'password') {
9497             return;
9498         }
9499         
9500         var isSelectAll = false;
9501         
9502         if(this.inputEl().dom.selectionEnd > 0){
9503             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9504         }
9505         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9506             event.preventDefault();
9507             this.setValue('');
9508             return;
9509         }
9510         
9511         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9512             
9513             event.preventDefault();
9514             // this is very hacky as keydown always get's upper case.
9515             //
9516             var cc = String.fromCharCode(event.getCharCode());
9517             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
9518             
9519         }
9520     },
9521     adjustWidth : function(tag, w){
9522         tag = tag.toLowerCase();
9523         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9524             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9525                 if(tag == 'input'){
9526                     return w + 2;
9527                 }
9528                 if(tag == 'textarea'){
9529                     return w-2;
9530                 }
9531             }else if(Roo.isOpera){
9532                 if(tag == 'input'){
9533                     return w + 2;
9534                 }
9535                 if(tag == 'textarea'){
9536                     return w-2;
9537                 }
9538             }
9539         }
9540         return w;
9541     },
9542     
9543     setFieldLabel : function(v)
9544     {
9545         if(!this.rendered){
9546             return;
9547         }
9548         
9549         if(this.indicator){
9550             var ar = this.el.select('label > span',true);
9551             
9552             if (ar.elements.length) {
9553                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9554                 this.fieldLabel = v;
9555                 return;
9556             }
9557             
9558             var br = this.el.select('label',true);
9559             
9560             if(br.elements.length) {
9561                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9562                 this.fieldLabel = v;
9563                 return;
9564             }
9565             
9566             Roo.log('Cannot Found any of label > span || label in input');
9567             return;
9568         }
9569         
9570         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9571         this.fieldLabel = v;
9572         
9573         
9574     }
9575 });
9576
9577  
9578 /*
9579  * - LGPL
9580  *
9581  * Input
9582  * 
9583  */
9584
9585 /**
9586  * @class Roo.bootstrap.TextArea
9587  * @extends Roo.bootstrap.Input
9588  * Bootstrap TextArea class
9589  * @cfg {Number} cols Specifies the visible width of a text area
9590  * @cfg {Number} rows Specifies the visible number of lines in a text area
9591  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9592  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9593  * @cfg {string} html text
9594  * 
9595  * @constructor
9596  * Create a new TextArea
9597  * @param {Object} config The config object
9598  */
9599
9600 Roo.bootstrap.TextArea = function(config){
9601     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9602    
9603 };
9604
9605 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
9606      
9607     cols : false,
9608     rows : 5,
9609     readOnly : false,
9610     warp : 'soft',
9611     resize : false,
9612     value: false,
9613     html: false,
9614     
9615     getAutoCreate : function(){
9616         
9617         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9618         
9619         var id = Roo.id();
9620         
9621         var cfg = {};
9622         
9623         if(this.inputType != 'hidden'){
9624             cfg.cls = 'form-group' //input-group
9625         }
9626         
9627         var input =  {
9628             tag: 'textarea',
9629             id : id,
9630             warp : this.warp,
9631             rows : this.rows,
9632             value : this.value || '',
9633             html: this.html || '',
9634             cls : 'form-control',
9635             placeholder : this.placeholder || '' 
9636             
9637         };
9638         
9639         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9640             input.maxLength = this.maxLength;
9641         }
9642         
9643         if(this.resize){
9644             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9645         }
9646         
9647         if(this.cols){
9648             input.cols = this.cols;
9649         }
9650         
9651         if (this.readOnly) {
9652             input.readonly = true;
9653         }
9654         
9655         if (this.name) {
9656             input.name = this.name;
9657         }
9658         
9659         if (this.size) {
9660             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9661         }
9662         
9663         var settings=this;
9664         ['xs','sm','md','lg'].map(function(size){
9665             if (settings[size]) {
9666                 cfg.cls += ' col-' + size + '-' + settings[size];
9667             }
9668         });
9669         
9670         var inputblock = input;
9671         
9672         if(this.hasFeedback && !this.allowBlank){
9673             
9674             var feedback = {
9675                 tag: 'span',
9676                 cls: 'glyphicon form-control-feedback'
9677             };
9678
9679             inputblock = {
9680                 cls : 'has-feedback',
9681                 cn :  [
9682                     input,
9683                     feedback
9684                 ] 
9685             };  
9686         }
9687         
9688         
9689         if (this.before || this.after) {
9690             
9691             inputblock = {
9692                 cls : 'input-group',
9693                 cn :  [] 
9694             };
9695             if (this.before) {
9696                 inputblock.cn.push({
9697                     tag :'span',
9698                     cls : 'input-group-addon',
9699                     html : this.before
9700                 });
9701             }
9702             
9703             inputblock.cn.push(input);
9704             
9705             if(this.hasFeedback && !this.allowBlank){
9706                 inputblock.cls += ' has-feedback';
9707                 inputblock.cn.push(feedback);
9708             }
9709             
9710             if (this.after) {
9711                 inputblock.cn.push({
9712                     tag :'span',
9713                     cls : 'input-group-addon',
9714                     html : this.after
9715                 });
9716             }
9717             
9718         }
9719         
9720         if (align ==='left' && this.fieldLabel.length) {
9721             cfg.cn = [
9722                 {
9723                     tag: 'label',
9724                     'for' :  id,
9725                     cls : 'control-label',
9726                     html : this.fieldLabel
9727                 },
9728                 {
9729                     cls : "",
9730                     cn: [
9731                         inputblock
9732                     ]
9733                 }
9734
9735             ];
9736             
9737             if(this.labelWidth > 12){
9738                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9739             }
9740
9741             if(this.labelWidth < 13 && this.labelmd == 0){
9742                 this.labelmd = this.labelWidth;
9743             }
9744
9745             if(this.labellg > 0){
9746                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9747                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9748             }
9749
9750             if(this.labelmd > 0){
9751                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9752                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9753             }
9754
9755             if(this.labelsm > 0){
9756                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9757                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9758             }
9759
9760             if(this.labelxs > 0){
9761                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9762                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9763             }
9764             
9765         } else if ( this.fieldLabel.length) {
9766             cfg.cn = [
9767
9768                {
9769                    tag: 'label',
9770                    //cls : 'input-group-addon',
9771                    html : this.fieldLabel
9772
9773                },
9774
9775                inputblock
9776
9777            ];
9778
9779         } else {
9780
9781             cfg.cn = [
9782
9783                 inputblock
9784
9785             ];
9786                 
9787         }
9788         
9789         if (this.disabled) {
9790             input.disabled=true;
9791         }
9792         
9793         return cfg;
9794         
9795     },
9796     /**
9797      * return the real textarea element.
9798      */
9799     inputEl: function ()
9800     {
9801         return this.el.select('textarea.form-control',true).first();
9802     },
9803     
9804     /**
9805      * Clear any invalid styles/messages for this field
9806      */
9807     clearInvalid : function()
9808     {
9809         
9810         if(!this.el || this.preventMark){ // not rendered
9811             return;
9812         }
9813         
9814         var label = this.el.select('label', true).first();
9815         var icon = this.el.select('i.fa-star', true).first();
9816         
9817         if(label && icon){
9818             icon.remove();
9819         }
9820         
9821         this.el.removeClass(this.invalidClass);
9822         
9823         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9824             
9825             var feedback = this.el.select('.form-control-feedback', true).first();
9826             
9827             if(feedback){
9828                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9829             }
9830             
9831         }
9832         
9833         this.fireEvent('valid', this);
9834     },
9835     
9836      /**
9837      * Mark this field as valid
9838      */
9839     markValid : function()
9840     {
9841         if(!this.el  || this.preventMark){ // not rendered
9842             return;
9843         }
9844         
9845         this.el.removeClass([this.invalidClass, this.validClass]);
9846         
9847         var feedback = this.el.select('.form-control-feedback', true).first();
9848             
9849         if(feedback){
9850             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9851         }
9852
9853         if(this.disabled || this.allowBlank){
9854             return;
9855         }
9856         
9857         var label = this.el.select('label', true).first();
9858         var icon = this.el.select('i.fa-star', true).first();
9859         
9860         if(label && icon){
9861             icon.remove();
9862         }
9863         
9864         this.el.addClass(this.validClass);
9865         
9866         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9867             
9868             var feedback = this.el.select('.form-control-feedback', true).first();
9869             
9870             if(feedback){
9871                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9872                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9873             }
9874             
9875         }
9876         
9877         this.fireEvent('valid', this);
9878     },
9879     
9880      /**
9881      * Mark this field as invalid
9882      * @param {String} msg The validation message
9883      */
9884     markInvalid : function(msg)
9885     {
9886         if(!this.el  || this.preventMark){ // not rendered
9887             return;
9888         }
9889         
9890         this.el.removeClass([this.invalidClass, this.validClass]);
9891         
9892         var feedback = this.el.select('.form-control-feedback', true).first();
9893             
9894         if(feedback){
9895             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9896         }
9897
9898         if(this.disabled || this.allowBlank){
9899             return;
9900         }
9901         
9902         var label = this.el.select('label', true).first();
9903         var icon = this.el.select('i.fa-star', true).first();
9904         
9905         if(!this.getValue().length && label && !icon){
9906             this.el.createChild({
9907                 tag : 'i',
9908                 cls : 'text-danger fa fa-lg fa-star',
9909                 tooltip : 'This field is required',
9910                 style : 'margin-right:5px;'
9911             }, label, true);
9912         }
9913
9914         this.el.addClass(this.invalidClass);
9915         
9916         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9917             
9918             var feedback = this.el.select('.form-control-feedback', true).first();
9919             
9920             if(feedback){
9921                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9922                 
9923                 if(this.getValue().length || this.forceFeedback){
9924                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9925                 }
9926                 
9927             }
9928             
9929         }
9930         
9931         this.fireEvent('invalid', this, msg);
9932     }
9933 });
9934
9935  
9936 /*
9937  * - LGPL
9938  *
9939  * trigger field - base class for combo..
9940  * 
9941  */
9942  
9943 /**
9944  * @class Roo.bootstrap.TriggerField
9945  * @extends Roo.bootstrap.Input
9946  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9947  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9948  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9949  * for which you can provide a custom implementation.  For example:
9950  * <pre><code>
9951 var trigger = new Roo.bootstrap.TriggerField();
9952 trigger.onTriggerClick = myTriggerFn;
9953 trigger.applyTo('my-field');
9954 </code></pre>
9955  *
9956  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9957  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9958  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
9959  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9960  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9961
9962  * @constructor
9963  * Create a new TriggerField.
9964  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9965  * to the base TextField)
9966  */
9967 Roo.bootstrap.TriggerField = function(config){
9968     this.mimicing = false;
9969     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9970 };
9971
9972 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
9973     /**
9974      * @cfg {String} triggerClass A CSS class to apply to the trigger
9975      */
9976      /**
9977      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9978      */
9979     hideTrigger:false,
9980
9981     /**
9982      * @cfg {Boolean} removable (true|false) special filter default false
9983      */
9984     removable : false,
9985     
9986     /** @cfg {Boolean} grow @hide */
9987     /** @cfg {Number} growMin @hide */
9988     /** @cfg {Number} growMax @hide */
9989
9990     /**
9991      * @hide 
9992      * @method
9993      */
9994     autoSize: Roo.emptyFn,
9995     // private
9996     monitorTab : true,
9997     // private
9998     deferHeight : true,
9999
10000     
10001     actionMode : 'wrap',
10002     
10003     caret : false,
10004     
10005     
10006     getAutoCreate : function(){
10007        
10008         var align = this.labelAlign || this.parentLabelAlign();
10009         
10010         var id = Roo.id();
10011         
10012         var cfg = {
10013             cls: 'form-group' //input-group
10014         };
10015         
10016         
10017         var input =  {
10018             tag: 'input',
10019             id : id,
10020             type : this.inputType,
10021             cls : 'form-control',
10022             autocomplete: 'new-password',
10023             placeholder : this.placeholder || '' 
10024             
10025         };
10026         if (this.name) {
10027             input.name = this.name;
10028         }
10029         if (this.size) {
10030             input.cls += ' input-' + this.size;
10031         }
10032         
10033         if (this.disabled) {
10034             input.disabled=true;
10035         }
10036         
10037         var inputblock = input;
10038         
10039         if(this.hasFeedback && !this.allowBlank){
10040             
10041             var feedback = {
10042                 tag: 'span',
10043                 cls: 'glyphicon form-control-feedback'
10044             };
10045             
10046             if(this.removable && !this.editable && !this.tickable){
10047                 inputblock = {
10048                     cls : 'has-feedback',
10049                     cn :  [
10050                         inputblock,
10051                         {
10052                             tag: 'button',
10053                             html : 'x',
10054                             cls : 'roo-combo-removable-btn close'
10055                         },
10056                         feedback
10057                     ] 
10058                 };
10059             } else {
10060                 inputblock = {
10061                     cls : 'has-feedback',
10062                     cn :  [
10063                         inputblock,
10064                         feedback
10065                     ] 
10066                 };
10067             }
10068
10069         } else {
10070             if(this.removable && !this.editable && !this.tickable){
10071                 inputblock = {
10072                     cls : 'roo-removable',
10073                     cn :  [
10074                         inputblock,
10075                         {
10076                             tag: 'button',
10077                             html : 'x',
10078                             cls : 'roo-combo-removable-btn close'
10079                         }
10080                     ] 
10081                 };
10082             }
10083         }
10084         
10085         if (this.before || this.after) {
10086             
10087             inputblock = {
10088                 cls : 'input-group',
10089                 cn :  [] 
10090             };
10091             if (this.before) {
10092                 inputblock.cn.push({
10093                     tag :'span',
10094                     cls : 'input-group-addon',
10095                     html : this.before
10096                 });
10097             }
10098             
10099             inputblock.cn.push(input);
10100             
10101             if(this.hasFeedback && !this.allowBlank){
10102                 inputblock.cls += ' has-feedback';
10103                 inputblock.cn.push(feedback);
10104             }
10105             
10106             if (this.after) {
10107                 inputblock.cn.push({
10108                     tag :'span',
10109                     cls : 'input-group-addon',
10110                     html : this.after
10111                 });
10112             }
10113             
10114         };
10115         
10116         var box = {
10117             tag: 'div',
10118             cn: [
10119                 {
10120                     tag: 'input',
10121                     type : 'hidden',
10122                     cls: 'form-hidden-field'
10123                 },
10124                 inputblock
10125             ]
10126             
10127         };
10128         
10129         if(this.multiple){
10130             box = {
10131                 tag: 'div',
10132                 cn: [
10133                     {
10134                         tag: 'input',
10135                         type : 'hidden',
10136                         cls: 'form-hidden-field'
10137                     },
10138                     {
10139                         tag: 'ul',
10140                         cls: 'roo-select2-choices',
10141                         cn:[
10142                             {
10143                                 tag: 'li',
10144                                 cls: 'roo-select2-search-field',
10145                                 cn: [
10146
10147                                     inputblock
10148                                 ]
10149                             }
10150                         ]
10151                     }
10152                 ]
10153             }
10154         };
10155         
10156         var combobox = {
10157             cls: 'roo-select2-container input-group',
10158             cn: [
10159                 box
10160 //                {
10161 //                    tag: 'ul',
10162 //                    cls: 'typeahead typeahead-long dropdown-menu',
10163 //                    style: 'display:none'
10164 //                }
10165             ]
10166         };
10167         
10168         if(!this.multiple && this.showToggleBtn){
10169             
10170             var caret = {
10171                         tag: 'span',
10172                         cls: 'caret'
10173              };
10174             if (this.caret != false) {
10175                 caret = {
10176                      tag: 'i',
10177                      cls: 'fa fa-' + this.caret
10178                 };
10179                 
10180             }
10181             
10182             combobox.cn.push({
10183                 tag :'span',
10184                 cls : 'input-group-addon btn dropdown-toggle',
10185                 cn : [
10186                     caret,
10187                     {
10188                         tag: 'span',
10189                         cls: 'combobox-clear',
10190                         cn  : [
10191                             {
10192                                 tag : 'i',
10193                                 cls: 'icon-remove'
10194                             }
10195                         ]
10196                     }
10197                 ]
10198
10199             })
10200         }
10201         
10202         if(this.multiple){
10203             combobox.cls += ' roo-select2-container-multi';
10204         }
10205         
10206         if (align ==='left' && this.fieldLabel.length) {
10207             
10208             cfg.cls += ' roo-form-group-label-left';
10209
10210             cfg.cn = [
10211                 {
10212                     tag : 'i',
10213                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10214                     tooltip : 'This field is required'
10215                 },
10216                 {
10217                     tag: 'label',
10218                     'for' :  id,
10219                     cls : 'control-label',
10220                     html : this.fieldLabel
10221
10222                 },
10223                 {
10224                     cls : "", 
10225                     cn: [
10226                         combobox
10227                     ]
10228                 }
10229
10230             ];
10231             
10232             var labelCfg = cfg.cn[1];
10233             var contentCfg = cfg.cn[2];
10234             
10235             if(this.indicatorpos == 'right'){
10236                 cfg.cn = [
10237                     {
10238                         tag: 'label',
10239                         'for' :  id,
10240                         cls : 'control-label',
10241                         cn : [
10242                             {
10243                                 tag : 'span',
10244                                 html : this.fieldLabel
10245                             },
10246                             {
10247                                 tag : 'i',
10248                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10249                                 tooltip : 'This field is required'
10250                             }
10251                         ]
10252                     },
10253                     {
10254                         cls : "", 
10255                         cn: [
10256                             combobox
10257                         ]
10258                     }
10259
10260                 ];
10261                 
10262                 labelCfg = cfg.cn[0];
10263                 contentCfg = cfg.cn[1];
10264             }
10265             
10266             if(this.labelWidth > 12){
10267                 labelCfg.style = "width: " + this.labelWidth + 'px';
10268             }
10269             
10270             if(this.labelWidth < 13 && this.labelmd == 0){
10271                 this.labelmd = this.labelWidth;
10272             }
10273             
10274             if(this.labellg > 0){
10275                 labelCfg.cls += ' col-lg-' + this.labellg;
10276                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10277             }
10278             
10279             if(this.labelmd > 0){
10280                 labelCfg.cls += ' col-md-' + this.labelmd;
10281                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10282             }
10283             
10284             if(this.labelsm > 0){
10285                 labelCfg.cls += ' col-sm-' + this.labelsm;
10286                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10287             }
10288             
10289             if(this.labelxs > 0){
10290                 labelCfg.cls += ' col-xs-' + this.labelxs;
10291                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10292             }
10293             
10294         } else if ( this.fieldLabel.length) {
10295 //                Roo.log(" label");
10296             cfg.cn = [
10297                 {
10298                    tag : 'i',
10299                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10300                    tooltip : 'This field is required'
10301                },
10302                {
10303                    tag: 'label',
10304                    //cls : 'input-group-addon',
10305                    html : this.fieldLabel
10306
10307                },
10308
10309                combobox
10310
10311             ];
10312             
10313             if(this.indicatorpos == 'right'){
10314                 
10315                 cfg.cn = [
10316                     {
10317                        tag: 'label',
10318                        cn : [
10319                            {
10320                                tag : 'span',
10321                                html : this.fieldLabel
10322                            },
10323                            {
10324                               tag : 'i',
10325                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10326                               tooltip : 'This field is required'
10327                            }
10328                        ]
10329
10330                     },
10331                     combobox
10332
10333                 ];
10334
10335             }
10336
10337         } else {
10338             
10339 //                Roo.log(" no label && no align");
10340                 cfg = combobox
10341                      
10342                 
10343         }
10344         
10345         var settings=this;
10346         ['xs','sm','md','lg'].map(function(size){
10347             if (settings[size]) {
10348                 cfg.cls += ' col-' + size + '-' + settings[size];
10349             }
10350         });
10351         
10352         return cfg;
10353         
10354     },
10355     
10356     
10357     
10358     // private
10359     onResize : function(w, h){
10360 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10361 //        if(typeof w == 'number'){
10362 //            var x = w - this.trigger.getWidth();
10363 //            this.inputEl().setWidth(this.adjustWidth('input', x));
10364 //            this.trigger.setStyle('left', x+'px');
10365 //        }
10366     },
10367
10368     // private
10369     adjustSize : Roo.BoxComponent.prototype.adjustSize,
10370
10371     // private
10372     getResizeEl : function(){
10373         return this.inputEl();
10374     },
10375
10376     // private
10377     getPositionEl : function(){
10378         return this.inputEl();
10379     },
10380
10381     // private
10382     alignErrorIcon : function(){
10383         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10384     },
10385
10386     // private
10387     initEvents : function(){
10388         
10389         this.createList();
10390         
10391         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10392         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10393         if(!this.multiple && this.showToggleBtn){
10394             this.trigger = this.el.select('span.dropdown-toggle',true).first();
10395             if(this.hideTrigger){
10396                 this.trigger.setDisplayed(false);
10397             }
10398             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10399         }
10400         
10401         if(this.multiple){
10402             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10403         }
10404         
10405         if(this.removable && !this.editable && !this.tickable){
10406             var close = this.closeTriggerEl();
10407             
10408             if(close){
10409                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10410                 close.on('click', this.removeBtnClick, this, close);
10411             }
10412         }
10413         
10414         //this.trigger.addClassOnOver('x-form-trigger-over');
10415         //this.trigger.addClassOnClick('x-form-trigger-click');
10416         
10417         //if(!this.width){
10418         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10419         //}
10420     },
10421     
10422     closeTriggerEl : function()
10423     {
10424         var close = this.el.select('.roo-combo-removable-btn', true).first();
10425         return close ? close : false;
10426     },
10427     
10428     removeBtnClick : function(e, h, el)
10429     {
10430         e.preventDefault();
10431         
10432         if(this.fireEvent("remove", this) !== false){
10433             this.reset();
10434             this.fireEvent("afterremove", this)
10435         }
10436     },
10437     
10438     createList : function()
10439     {
10440         this.list = Roo.get(document.body).createChild({
10441             tag: 'ul',
10442             cls: 'typeahead typeahead-long dropdown-menu',
10443             style: 'display:none'
10444         });
10445         
10446         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10447         
10448     },
10449
10450     // private
10451     initTrigger : function(){
10452        
10453     },
10454
10455     // private
10456     onDestroy : function(){
10457         if(this.trigger){
10458             this.trigger.removeAllListeners();
10459           //  this.trigger.remove();
10460         }
10461         //if(this.wrap){
10462         //    this.wrap.remove();
10463         //}
10464         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10465     },
10466
10467     // private
10468     onFocus : function(){
10469         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10470         /*
10471         if(!this.mimicing){
10472             this.wrap.addClass('x-trigger-wrap-focus');
10473             this.mimicing = true;
10474             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10475             if(this.monitorTab){
10476                 this.el.on("keydown", this.checkTab, this);
10477             }
10478         }
10479         */
10480     },
10481
10482     // private
10483     checkTab : function(e){
10484         if(e.getKey() == e.TAB){
10485             this.triggerBlur();
10486         }
10487     },
10488
10489     // private
10490     onBlur : function(){
10491         // do nothing
10492     },
10493
10494     // private
10495     mimicBlur : function(e, t){
10496         /*
10497         if(!this.wrap.contains(t) && this.validateBlur()){
10498             this.triggerBlur();
10499         }
10500         */
10501     },
10502
10503     // private
10504     triggerBlur : function(){
10505         this.mimicing = false;
10506         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10507         if(this.monitorTab){
10508             this.el.un("keydown", this.checkTab, this);
10509         }
10510         //this.wrap.removeClass('x-trigger-wrap-focus');
10511         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10512     },
10513
10514     // private
10515     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10516     validateBlur : function(e, t){
10517         return true;
10518     },
10519
10520     // private
10521     onDisable : function(){
10522         this.inputEl().dom.disabled = true;
10523         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10524         //if(this.wrap){
10525         //    this.wrap.addClass('x-item-disabled');
10526         //}
10527     },
10528
10529     // private
10530     onEnable : function(){
10531         this.inputEl().dom.disabled = false;
10532         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10533         //if(this.wrap){
10534         //    this.el.removeClass('x-item-disabled');
10535         //}
10536     },
10537
10538     // private
10539     onShow : function(){
10540         var ae = this.getActionEl();
10541         
10542         if(ae){
10543             ae.dom.style.display = '';
10544             ae.dom.style.visibility = 'visible';
10545         }
10546     },
10547
10548     // private
10549     
10550     onHide : function(){
10551         var ae = this.getActionEl();
10552         ae.dom.style.display = 'none';
10553     },
10554
10555     /**
10556      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
10557      * by an implementing function.
10558      * @method
10559      * @param {EventObject} e
10560      */
10561     onTriggerClick : Roo.emptyFn
10562 });
10563  /*
10564  * Based on:
10565  * Ext JS Library 1.1.1
10566  * Copyright(c) 2006-2007, Ext JS, LLC.
10567  *
10568  * Originally Released Under LGPL - original licence link has changed is not relivant.
10569  *
10570  * Fork - LGPL
10571  * <script type="text/javascript">
10572  */
10573
10574
10575 /**
10576  * @class Roo.data.SortTypes
10577  * @singleton
10578  * Defines the default sorting (casting?) comparison functions used when sorting data.
10579  */
10580 Roo.data.SortTypes = {
10581     /**
10582      * Default sort that does nothing
10583      * @param {Mixed} s The value being converted
10584      * @return {Mixed} The comparison value
10585      */
10586     none : function(s){
10587         return s;
10588     },
10589     
10590     /**
10591      * The regular expression used to strip tags
10592      * @type {RegExp}
10593      * @property
10594      */
10595     stripTagsRE : /<\/?[^>]+>/gi,
10596     
10597     /**
10598      * Strips all HTML tags to sort on text only
10599      * @param {Mixed} s The value being converted
10600      * @return {String} The comparison value
10601      */
10602     asText : function(s){
10603         return String(s).replace(this.stripTagsRE, "");
10604     },
10605     
10606     /**
10607      * Strips all HTML tags to sort on text only - Case insensitive
10608      * @param {Mixed} s The value being converted
10609      * @return {String} The comparison value
10610      */
10611     asUCText : function(s){
10612         return String(s).toUpperCase().replace(this.stripTagsRE, "");
10613     },
10614     
10615     /**
10616      * Case insensitive string
10617      * @param {Mixed} s The value being converted
10618      * @return {String} The comparison value
10619      */
10620     asUCString : function(s) {
10621         return String(s).toUpperCase();
10622     },
10623     
10624     /**
10625      * Date sorting
10626      * @param {Mixed} s The value being converted
10627      * @return {Number} The comparison value
10628      */
10629     asDate : function(s) {
10630         if(!s){
10631             return 0;
10632         }
10633         if(s instanceof Date){
10634             return s.getTime();
10635         }
10636         return Date.parse(String(s));
10637     },
10638     
10639     /**
10640      * Float sorting
10641      * @param {Mixed} s The value being converted
10642      * @return {Float} The comparison value
10643      */
10644     asFloat : function(s) {
10645         var val = parseFloat(String(s).replace(/,/g, ""));
10646         if(isNaN(val)) {
10647             val = 0;
10648         }
10649         return val;
10650     },
10651     
10652     /**
10653      * Integer sorting
10654      * @param {Mixed} s The value being converted
10655      * @return {Number} The comparison value
10656      */
10657     asInt : function(s) {
10658         var val = parseInt(String(s).replace(/,/g, ""));
10659         if(isNaN(val)) {
10660             val = 0;
10661         }
10662         return val;
10663     }
10664 };/*
10665  * Based on:
10666  * Ext JS Library 1.1.1
10667  * Copyright(c) 2006-2007, Ext JS, LLC.
10668  *
10669  * Originally Released Under LGPL - original licence link has changed is not relivant.
10670  *
10671  * Fork - LGPL
10672  * <script type="text/javascript">
10673  */
10674
10675 /**
10676 * @class Roo.data.Record
10677  * Instances of this class encapsulate both record <em>definition</em> information, and record
10678  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10679  * to access Records cached in an {@link Roo.data.Store} object.<br>
10680  * <p>
10681  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10682  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10683  * objects.<br>
10684  * <p>
10685  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10686  * @constructor
10687  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10688  * {@link #create}. The parameters are the same.
10689  * @param {Array} data An associative Array of data values keyed by the field name.
10690  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10691  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10692  * not specified an integer id is generated.
10693  */
10694 Roo.data.Record = function(data, id){
10695     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10696     this.data = data;
10697 };
10698
10699 /**
10700  * Generate a constructor for a specific record layout.
10701  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10702  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10703  * Each field definition object may contain the following properties: <ul>
10704  * <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,
10705  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10706  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10707  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10708  * is being used, then this is a string containing the javascript expression to reference the data relative to 
10709  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10710  * to the data item relative to the record element. If the mapping expression is the same as the field name,
10711  * this may be omitted.</p></li>
10712  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10713  * <ul><li>auto (Default, implies no conversion)</li>
10714  * <li>string</li>
10715  * <li>int</li>
10716  * <li>float</li>
10717  * <li>boolean</li>
10718  * <li>date</li></ul></p></li>
10719  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10720  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10721  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10722  * by the Reader into an object that will be stored in the Record. It is passed the
10723  * following parameters:<ul>
10724  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10725  * </ul></p></li>
10726  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10727  * </ul>
10728  * <br>usage:<br><pre><code>
10729 var TopicRecord = Roo.data.Record.create(
10730     {name: 'title', mapping: 'topic_title'},
10731     {name: 'author', mapping: 'username'},
10732     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10733     {name: 'lastPost', mapping: 'post_time', type: 'date'},
10734     {name: 'lastPoster', mapping: 'user2'},
10735     {name: 'excerpt', mapping: 'post_text'}
10736 );
10737
10738 var myNewRecord = new TopicRecord({
10739     title: 'Do my job please',
10740     author: 'noobie',
10741     totalPosts: 1,
10742     lastPost: new Date(),
10743     lastPoster: 'Animal',
10744     excerpt: 'No way dude!'
10745 });
10746 myStore.add(myNewRecord);
10747 </code></pre>
10748  * @method create
10749  * @static
10750  */
10751 Roo.data.Record.create = function(o){
10752     var f = function(){
10753         f.superclass.constructor.apply(this, arguments);
10754     };
10755     Roo.extend(f, Roo.data.Record);
10756     var p = f.prototype;
10757     p.fields = new Roo.util.MixedCollection(false, function(field){
10758         return field.name;
10759     });
10760     for(var i = 0, len = o.length; i < len; i++){
10761         p.fields.add(new Roo.data.Field(o[i]));
10762     }
10763     f.getField = function(name){
10764         return p.fields.get(name);  
10765     };
10766     return f;
10767 };
10768
10769 Roo.data.Record.AUTO_ID = 1000;
10770 Roo.data.Record.EDIT = 'edit';
10771 Roo.data.Record.REJECT = 'reject';
10772 Roo.data.Record.COMMIT = 'commit';
10773
10774 Roo.data.Record.prototype = {
10775     /**
10776      * Readonly flag - true if this record has been modified.
10777      * @type Boolean
10778      */
10779     dirty : false,
10780     editing : false,
10781     error: null,
10782     modified: null,
10783
10784     // private
10785     join : function(store){
10786         this.store = store;
10787     },
10788
10789     /**
10790      * Set the named field to the specified value.
10791      * @param {String} name The name of the field to set.
10792      * @param {Object} value The value to set the field to.
10793      */
10794     set : function(name, value){
10795         if(this.data[name] == value){
10796             return;
10797         }
10798         this.dirty = true;
10799         if(!this.modified){
10800             this.modified = {};
10801         }
10802         if(typeof this.modified[name] == 'undefined'){
10803             this.modified[name] = this.data[name];
10804         }
10805         this.data[name] = value;
10806         if(!this.editing && this.store){
10807             this.store.afterEdit(this);
10808         }       
10809     },
10810
10811     /**
10812      * Get the value of the named field.
10813      * @param {String} name The name of the field to get the value of.
10814      * @return {Object} The value of the field.
10815      */
10816     get : function(name){
10817         return this.data[name]; 
10818     },
10819
10820     // private
10821     beginEdit : function(){
10822         this.editing = true;
10823         this.modified = {}; 
10824     },
10825
10826     // private
10827     cancelEdit : function(){
10828         this.editing = false;
10829         delete this.modified;
10830     },
10831
10832     // private
10833     endEdit : function(){
10834         this.editing = false;
10835         if(this.dirty && this.store){
10836             this.store.afterEdit(this);
10837         }
10838     },
10839
10840     /**
10841      * Usually called by the {@link Roo.data.Store} which owns the Record.
10842      * Rejects all changes made to the Record since either creation, or the last commit operation.
10843      * Modified fields are reverted to their original values.
10844      * <p>
10845      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10846      * of reject operations.
10847      */
10848     reject : function(){
10849         var m = this.modified;
10850         for(var n in m){
10851             if(typeof m[n] != "function"){
10852                 this.data[n] = m[n];
10853             }
10854         }
10855         this.dirty = false;
10856         delete this.modified;
10857         this.editing = false;
10858         if(this.store){
10859             this.store.afterReject(this);
10860         }
10861     },
10862
10863     /**
10864      * Usually called by the {@link Roo.data.Store} which owns the Record.
10865      * Commits all changes made to the Record since either creation, or the last commit operation.
10866      * <p>
10867      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10868      * of commit operations.
10869      */
10870     commit : function(){
10871         this.dirty = false;
10872         delete this.modified;
10873         this.editing = false;
10874         if(this.store){
10875             this.store.afterCommit(this);
10876         }
10877     },
10878
10879     // private
10880     hasError : function(){
10881         return this.error != null;
10882     },
10883
10884     // private
10885     clearError : function(){
10886         this.error = null;
10887     },
10888
10889     /**
10890      * Creates a copy of this record.
10891      * @param {String} id (optional) A new record id if you don't want to use this record's id
10892      * @return {Record}
10893      */
10894     copy : function(newId) {
10895         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10896     }
10897 };/*
10898  * Based on:
10899  * Ext JS Library 1.1.1
10900  * Copyright(c) 2006-2007, Ext JS, LLC.
10901  *
10902  * Originally Released Under LGPL - original licence link has changed is not relivant.
10903  *
10904  * Fork - LGPL
10905  * <script type="text/javascript">
10906  */
10907
10908
10909
10910 /**
10911  * @class Roo.data.Store
10912  * @extends Roo.util.Observable
10913  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10914  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10915  * <p>
10916  * 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
10917  * has no knowledge of the format of the data returned by the Proxy.<br>
10918  * <p>
10919  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10920  * instances from the data object. These records are cached and made available through accessor functions.
10921  * @constructor
10922  * Creates a new Store.
10923  * @param {Object} config A config object containing the objects needed for the Store to access data,
10924  * and read the data into Records.
10925  */
10926 Roo.data.Store = function(config){
10927     this.data = new Roo.util.MixedCollection(false);
10928     this.data.getKey = function(o){
10929         return o.id;
10930     };
10931     this.baseParams = {};
10932     // private
10933     this.paramNames = {
10934         "start" : "start",
10935         "limit" : "limit",
10936         "sort" : "sort",
10937         "dir" : "dir",
10938         "multisort" : "_multisort"
10939     };
10940
10941     if(config && config.data){
10942         this.inlineData = config.data;
10943         delete config.data;
10944     }
10945
10946     Roo.apply(this, config);
10947     
10948     if(this.reader){ // reader passed
10949         this.reader = Roo.factory(this.reader, Roo.data);
10950         this.reader.xmodule = this.xmodule || false;
10951         if(!this.recordType){
10952             this.recordType = this.reader.recordType;
10953         }
10954         if(this.reader.onMetaChange){
10955             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10956         }
10957     }
10958
10959     if(this.recordType){
10960         this.fields = this.recordType.prototype.fields;
10961     }
10962     this.modified = [];
10963
10964     this.addEvents({
10965         /**
10966          * @event datachanged
10967          * Fires when the data cache has changed, and a widget which is using this Store
10968          * as a Record cache should refresh its view.
10969          * @param {Store} this
10970          */
10971         datachanged : true,
10972         /**
10973          * @event metachange
10974          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10975          * @param {Store} this
10976          * @param {Object} meta The JSON metadata
10977          */
10978         metachange : true,
10979         /**
10980          * @event add
10981          * Fires when Records have been added to the Store
10982          * @param {Store} this
10983          * @param {Roo.data.Record[]} records The array of Records added
10984          * @param {Number} index The index at which the record(s) were added
10985          */
10986         add : true,
10987         /**
10988          * @event remove
10989          * Fires when a Record has been removed from the Store
10990          * @param {Store} this
10991          * @param {Roo.data.Record} record The Record that was removed
10992          * @param {Number} index The index at which the record was removed
10993          */
10994         remove : true,
10995         /**
10996          * @event update
10997          * Fires when a Record has been updated
10998          * @param {Store} this
10999          * @param {Roo.data.Record} record The Record that was updated
11000          * @param {String} operation The update operation being performed.  Value may be one of:
11001          * <pre><code>
11002  Roo.data.Record.EDIT
11003  Roo.data.Record.REJECT
11004  Roo.data.Record.COMMIT
11005          * </code></pre>
11006          */
11007         update : true,
11008         /**
11009          * @event clear
11010          * Fires when the data cache has been cleared.
11011          * @param {Store} this
11012          */
11013         clear : true,
11014         /**
11015          * @event beforeload
11016          * Fires before a request is made for a new data object.  If the beforeload handler returns false
11017          * the load action will be canceled.
11018          * @param {Store} this
11019          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11020          */
11021         beforeload : true,
11022         /**
11023          * @event beforeloadadd
11024          * Fires after a new set of Records has been loaded.
11025          * @param {Store} this
11026          * @param {Roo.data.Record[]} records The Records that were loaded
11027          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11028          */
11029         beforeloadadd : true,
11030         /**
11031          * @event load
11032          * Fires after a new set of Records has been loaded, before they are added to the store.
11033          * @param {Store} this
11034          * @param {Roo.data.Record[]} records The Records that were loaded
11035          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11036          * @params {Object} return from reader
11037          */
11038         load : true,
11039         /**
11040          * @event loadexception
11041          * Fires if an exception occurs in the Proxy during loading.
11042          * Called with the signature of the Proxy's "loadexception" event.
11043          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11044          * 
11045          * @param {Proxy} 
11046          * @param {Object} return from JsonData.reader() - success, totalRecords, records
11047          * @param {Object} load options 
11048          * @param {Object} jsonData from your request (normally this contains the Exception)
11049          */
11050         loadexception : true
11051     });
11052     
11053     if(this.proxy){
11054         this.proxy = Roo.factory(this.proxy, Roo.data);
11055         this.proxy.xmodule = this.xmodule || false;
11056         this.relayEvents(this.proxy,  ["loadexception"]);
11057     }
11058     this.sortToggle = {};
11059     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11060
11061     Roo.data.Store.superclass.constructor.call(this);
11062
11063     if(this.inlineData){
11064         this.loadData(this.inlineData);
11065         delete this.inlineData;
11066     }
11067 };
11068
11069 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11070      /**
11071     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
11072     * without a remote query - used by combo/forms at present.
11073     */
11074     
11075     /**
11076     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11077     */
11078     /**
11079     * @cfg {Array} data Inline data to be loaded when the store is initialized.
11080     */
11081     /**
11082     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11083     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11084     */
11085     /**
11086     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11087     * on any HTTP request
11088     */
11089     /**
11090     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11091     */
11092     /**
11093     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11094     */
11095     multiSort: false,
11096     /**
11097     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11098     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11099     */
11100     remoteSort : false,
11101
11102     /**
11103     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11104      * loaded or when a record is removed. (defaults to false).
11105     */
11106     pruneModifiedRecords : false,
11107
11108     // private
11109     lastOptions : null,
11110
11111     /**
11112      * Add Records to the Store and fires the add event.
11113      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11114      */
11115     add : function(records){
11116         records = [].concat(records);
11117         for(var i = 0, len = records.length; i < len; i++){
11118             records[i].join(this);
11119         }
11120         var index = this.data.length;
11121         this.data.addAll(records);
11122         this.fireEvent("add", this, records, index);
11123     },
11124
11125     /**
11126      * Remove a Record from the Store and fires the remove event.
11127      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11128      */
11129     remove : function(record){
11130         var index = this.data.indexOf(record);
11131         this.data.removeAt(index);
11132  
11133         if(this.pruneModifiedRecords){
11134             this.modified.remove(record);
11135         }
11136         this.fireEvent("remove", this, record, index);
11137     },
11138
11139     /**
11140      * Remove all Records from the Store and fires the clear event.
11141      */
11142     removeAll : function(){
11143         this.data.clear();
11144         if(this.pruneModifiedRecords){
11145             this.modified = [];
11146         }
11147         this.fireEvent("clear", this);
11148     },
11149
11150     /**
11151      * Inserts Records to the Store at the given index and fires the add event.
11152      * @param {Number} index The start index at which to insert the passed Records.
11153      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11154      */
11155     insert : function(index, records){
11156         records = [].concat(records);
11157         for(var i = 0, len = records.length; i < len; i++){
11158             this.data.insert(index, records[i]);
11159             records[i].join(this);
11160         }
11161         this.fireEvent("add", this, records, index);
11162     },
11163
11164     /**
11165      * Get the index within the cache of the passed Record.
11166      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11167      * @return {Number} The index of the passed Record. Returns -1 if not found.
11168      */
11169     indexOf : function(record){
11170         return this.data.indexOf(record);
11171     },
11172
11173     /**
11174      * Get the index within the cache of the Record with the passed id.
11175      * @param {String} id The id of the Record to find.
11176      * @return {Number} The index of the Record. Returns -1 if not found.
11177      */
11178     indexOfId : function(id){
11179         return this.data.indexOfKey(id);
11180     },
11181
11182     /**
11183      * Get the Record with the specified id.
11184      * @param {String} id The id of the Record to find.
11185      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11186      */
11187     getById : function(id){
11188         return this.data.key(id);
11189     },
11190
11191     /**
11192      * Get the Record at the specified index.
11193      * @param {Number} index The index of the Record to find.
11194      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11195      */
11196     getAt : function(index){
11197         return this.data.itemAt(index);
11198     },
11199
11200     /**
11201      * Returns a range of Records between specified indices.
11202      * @param {Number} startIndex (optional) The starting index (defaults to 0)
11203      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11204      * @return {Roo.data.Record[]} An array of Records
11205      */
11206     getRange : function(start, end){
11207         return this.data.getRange(start, end);
11208     },
11209
11210     // private
11211     storeOptions : function(o){
11212         o = Roo.apply({}, o);
11213         delete o.callback;
11214         delete o.scope;
11215         this.lastOptions = o;
11216     },
11217
11218     /**
11219      * Loads the Record cache from the configured Proxy using the configured Reader.
11220      * <p>
11221      * If using remote paging, then the first load call must specify the <em>start</em>
11222      * and <em>limit</em> properties in the options.params property to establish the initial
11223      * position within the dataset, and the number of Records to cache on each read from the Proxy.
11224      * <p>
11225      * <strong>It is important to note that for remote data sources, loading is asynchronous,
11226      * and this call will return before the new data has been loaded. Perform any post-processing
11227      * in a callback function, or in a "load" event handler.</strong>
11228      * <p>
11229      * @param {Object} options An object containing properties which control loading options:<ul>
11230      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11231      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11232      * passed the following arguments:<ul>
11233      * <li>r : Roo.data.Record[]</li>
11234      * <li>options: Options object from the load call</li>
11235      * <li>success: Boolean success indicator</li></ul></li>
11236      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11237      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11238      * </ul>
11239      */
11240     load : function(options){
11241         options = options || {};
11242         if(this.fireEvent("beforeload", this, options) !== false){
11243             this.storeOptions(options);
11244             var p = Roo.apply(options.params || {}, this.baseParams);
11245             // if meta was not loaded from remote source.. try requesting it.
11246             if (!this.reader.metaFromRemote) {
11247                 p._requestMeta = 1;
11248             }
11249             if(this.sortInfo && this.remoteSort){
11250                 var pn = this.paramNames;
11251                 p[pn["sort"]] = this.sortInfo.field;
11252                 p[pn["dir"]] = this.sortInfo.direction;
11253             }
11254             if (this.multiSort) {
11255                 var pn = this.paramNames;
11256                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11257             }
11258             
11259             this.proxy.load(p, this.reader, this.loadRecords, this, options);
11260         }
11261     },
11262
11263     /**
11264      * Reloads the Record cache from the configured Proxy using the configured Reader and
11265      * the options from the last load operation performed.
11266      * @param {Object} options (optional) An object containing properties which may override the options
11267      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11268      * the most recently used options are reused).
11269      */
11270     reload : function(options){
11271         this.load(Roo.applyIf(options||{}, this.lastOptions));
11272     },
11273
11274     // private
11275     // Called as a callback by the Reader during a load operation.
11276     loadRecords : function(o, options, success){
11277         if(!o || success === false){
11278             if(success !== false){
11279                 this.fireEvent("load", this, [], options, o);
11280             }
11281             if(options.callback){
11282                 options.callback.call(options.scope || this, [], options, false);
11283             }
11284             return;
11285         }
11286         // if data returned failure - throw an exception.
11287         if (o.success === false) {
11288             // show a message if no listener is registered.
11289             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11290                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11291             }
11292             // loadmask wil be hooked into this..
11293             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11294             return;
11295         }
11296         var r = o.records, t = o.totalRecords || r.length;
11297         
11298         this.fireEvent("beforeloadadd", this, r, options, o);
11299         
11300         if(!options || options.add !== true){
11301             if(this.pruneModifiedRecords){
11302                 this.modified = [];
11303             }
11304             for(var i = 0, len = r.length; i < len; i++){
11305                 r[i].join(this);
11306             }
11307             if(this.snapshot){
11308                 this.data = this.snapshot;
11309                 delete this.snapshot;
11310             }
11311             this.data.clear();
11312             this.data.addAll(r);
11313             this.totalLength = t;
11314             this.applySort();
11315             this.fireEvent("datachanged", this);
11316         }else{
11317             this.totalLength = Math.max(t, this.data.length+r.length);
11318             this.add(r);
11319         }
11320         
11321         if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11322                 
11323             var e = new Roo.data.Record({});
11324
11325             e.set(this.parent.displayField, this.parent.emptyTitle);
11326             e.set(this.parent.valueField, '');
11327
11328             this.insert(0, e);
11329         }
11330             
11331         this.fireEvent("load", this, r, options, o);
11332         if(options.callback){
11333             options.callback.call(options.scope || this, r, options, true);
11334         }
11335     },
11336
11337
11338     /**
11339      * Loads data from a passed data block. A Reader which understands the format of the data
11340      * must have been configured in the constructor.
11341      * @param {Object} data The data block from which to read the Records.  The format of the data expected
11342      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11343      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11344      */
11345     loadData : function(o, append){
11346         var r = this.reader.readRecords(o);
11347         this.loadRecords(r, {add: append}, true);
11348     },
11349
11350     /**
11351      * Gets the number of cached records.
11352      * <p>
11353      * <em>If using paging, this may not be the total size of the dataset. If the data object
11354      * used by the Reader contains the dataset size, then the getTotalCount() function returns
11355      * the data set size</em>
11356      */
11357     getCount : function(){
11358         return this.data.length || 0;
11359     },
11360
11361     /**
11362      * Gets the total number of records in the dataset as returned by the server.
11363      * <p>
11364      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11365      * the dataset size</em>
11366      */
11367     getTotalCount : function(){
11368         return this.totalLength || 0;
11369     },
11370
11371     /**
11372      * Returns the sort state of the Store as an object with two properties:
11373      * <pre><code>
11374  field {String} The name of the field by which the Records are sorted
11375  direction {String} The sort order, "ASC" or "DESC"
11376      * </code></pre>
11377      */
11378     getSortState : function(){
11379         return this.sortInfo;
11380     },
11381
11382     // private
11383     applySort : function(){
11384         if(this.sortInfo && !this.remoteSort){
11385             var s = this.sortInfo, f = s.field;
11386             var st = this.fields.get(f).sortType;
11387             var fn = function(r1, r2){
11388                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11389                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11390             };
11391             this.data.sort(s.direction, fn);
11392             if(this.snapshot && this.snapshot != this.data){
11393                 this.snapshot.sort(s.direction, fn);
11394             }
11395         }
11396     },
11397
11398     /**
11399      * Sets the default sort column and order to be used by the next load operation.
11400      * @param {String} fieldName The name of the field to sort by.
11401      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11402      */
11403     setDefaultSort : function(field, dir){
11404         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11405     },
11406
11407     /**
11408      * Sort the Records.
11409      * If remote sorting is used, the sort is performed on the server, and the cache is
11410      * reloaded. If local sorting is used, the cache is sorted internally.
11411      * @param {String} fieldName The name of the field to sort by.
11412      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11413      */
11414     sort : function(fieldName, dir){
11415         var f = this.fields.get(fieldName);
11416         if(!dir){
11417             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11418             
11419             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11420                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11421             }else{
11422                 dir = f.sortDir;
11423             }
11424         }
11425         this.sortToggle[f.name] = dir;
11426         this.sortInfo = {field: f.name, direction: dir};
11427         if(!this.remoteSort){
11428             this.applySort();
11429             this.fireEvent("datachanged", this);
11430         }else{
11431             this.load(this.lastOptions);
11432         }
11433     },
11434
11435     /**
11436      * Calls the specified function for each of the Records in the cache.
11437      * @param {Function} fn The function to call. The Record is passed as the first parameter.
11438      * Returning <em>false</em> aborts and exits the iteration.
11439      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11440      */
11441     each : function(fn, scope){
11442         this.data.each(fn, scope);
11443     },
11444
11445     /**
11446      * Gets all records modified since the last commit.  Modified records are persisted across load operations
11447      * (e.g., during paging).
11448      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11449      */
11450     getModifiedRecords : function(){
11451         return this.modified;
11452     },
11453
11454     // private
11455     createFilterFn : function(property, value, anyMatch){
11456         if(!value.exec){ // not a regex
11457             value = String(value);
11458             if(value.length == 0){
11459                 return false;
11460             }
11461             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11462         }
11463         return function(r){
11464             return value.test(r.data[property]);
11465         };
11466     },
11467
11468     /**
11469      * Sums the value of <i>property</i> for each record between start and end and returns the result.
11470      * @param {String} property A field on your records
11471      * @param {Number} start The record index to start at (defaults to 0)
11472      * @param {Number} end The last record index to include (defaults to length - 1)
11473      * @return {Number} The sum
11474      */
11475     sum : function(property, start, end){
11476         var rs = this.data.items, v = 0;
11477         start = start || 0;
11478         end = (end || end === 0) ? end : rs.length-1;
11479
11480         for(var i = start; i <= end; i++){
11481             v += (rs[i].data[property] || 0);
11482         }
11483         return v;
11484     },
11485
11486     /**
11487      * Filter the records by a specified property.
11488      * @param {String} field A field on your records
11489      * @param {String/RegExp} value Either a string that the field
11490      * should start with or a RegExp to test against the field
11491      * @param {Boolean} anyMatch True to match any part not just the beginning
11492      */
11493     filter : function(property, value, anyMatch){
11494         var fn = this.createFilterFn(property, value, anyMatch);
11495         return fn ? this.filterBy(fn) : this.clearFilter();
11496     },
11497
11498     /**
11499      * Filter by a function. The specified function will be called with each
11500      * record in this data source. If the function returns true the record is included,
11501      * otherwise it is filtered.
11502      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11503      * @param {Object} scope (optional) The scope of the function (defaults to this)
11504      */
11505     filterBy : function(fn, scope){
11506         this.snapshot = this.snapshot || this.data;
11507         this.data = this.queryBy(fn, scope||this);
11508         this.fireEvent("datachanged", this);
11509     },
11510
11511     /**
11512      * Query the records by a specified property.
11513      * @param {String} field A field on your records
11514      * @param {String/RegExp} value Either a string that the field
11515      * should start with or a RegExp to test against the field
11516      * @param {Boolean} anyMatch True to match any part not just the beginning
11517      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11518      */
11519     query : function(property, value, anyMatch){
11520         var fn = this.createFilterFn(property, value, anyMatch);
11521         return fn ? this.queryBy(fn) : this.data.clone();
11522     },
11523
11524     /**
11525      * Query by a function. The specified function will be called with each
11526      * record in this data source. If the function returns true the record is included
11527      * in the results.
11528      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11529      * @param {Object} scope (optional) The scope of the function (defaults to this)
11530       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11531      **/
11532     queryBy : function(fn, scope){
11533         var data = this.snapshot || this.data;
11534         return data.filterBy(fn, scope||this);
11535     },
11536
11537     /**
11538      * Collects unique values for a particular dataIndex from this store.
11539      * @param {String} dataIndex The property to collect
11540      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11541      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11542      * @return {Array} An array of the unique values
11543      **/
11544     collect : function(dataIndex, allowNull, bypassFilter){
11545         var d = (bypassFilter === true && this.snapshot) ?
11546                 this.snapshot.items : this.data.items;
11547         var v, sv, r = [], l = {};
11548         for(var i = 0, len = d.length; i < len; i++){
11549             v = d[i].data[dataIndex];
11550             sv = String(v);
11551             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11552                 l[sv] = true;
11553                 r[r.length] = v;
11554             }
11555         }
11556         return r;
11557     },
11558
11559     /**
11560      * Revert to a view of the Record cache with no filtering applied.
11561      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11562      */
11563     clearFilter : function(suppressEvent){
11564         if(this.snapshot && this.snapshot != this.data){
11565             this.data = this.snapshot;
11566             delete this.snapshot;
11567             if(suppressEvent !== true){
11568                 this.fireEvent("datachanged", this);
11569             }
11570         }
11571     },
11572
11573     // private
11574     afterEdit : function(record){
11575         if(this.modified.indexOf(record) == -1){
11576             this.modified.push(record);
11577         }
11578         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11579     },
11580     
11581     // private
11582     afterReject : function(record){
11583         this.modified.remove(record);
11584         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11585     },
11586
11587     // private
11588     afterCommit : function(record){
11589         this.modified.remove(record);
11590         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11591     },
11592
11593     /**
11594      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11595      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11596      */
11597     commitChanges : function(){
11598         var m = this.modified.slice(0);
11599         this.modified = [];
11600         for(var i = 0, len = m.length; i < len; i++){
11601             m[i].commit();
11602         }
11603     },
11604
11605     /**
11606      * Cancel outstanding changes on all changed records.
11607      */
11608     rejectChanges : function(){
11609         var m = this.modified.slice(0);
11610         this.modified = [];
11611         for(var i = 0, len = m.length; i < len; i++){
11612             m[i].reject();
11613         }
11614     },
11615
11616     onMetaChange : function(meta, rtype, o){
11617         this.recordType = rtype;
11618         this.fields = rtype.prototype.fields;
11619         delete this.snapshot;
11620         this.sortInfo = meta.sortInfo || this.sortInfo;
11621         this.modified = [];
11622         this.fireEvent('metachange', this, this.reader.meta);
11623     },
11624     
11625     moveIndex : function(data, type)
11626     {
11627         var index = this.indexOf(data);
11628         
11629         var newIndex = index + type;
11630         
11631         this.remove(data);
11632         
11633         this.insert(newIndex, data);
11634         
11635     }
11636 });/*
11637  * Based on:
11638  * Ext JS Library 1.1.1
11639  * Copyright(c) 2006-2007, Ext JS, LLC.
11640  *
11641  * Originally Released Under LGPL - original licence link has changed is not relivant.
11642  *
11643  * Fork - LGPL
11644  * <script type="text/javascript">
11645  */
11646
11647 /**
11648  * @class Roo.data.SimpleStore
11649  * @extends Roo.data.Store
11650  * Small helper class to make creating Stores from Array data easier.
11651  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11652  * @cfg {Array} fields An array of field definition objects, or field name strings.
11653  * @cfg {Array} data The multi-dimensional array of data
11654  * @constructor
11655  * @param {Object} config
11656  */
11657 Roo.data.SimpleStore = function(config){
11658     Roo.data.SimpleStore.superclass.constructor.call(this, {
11659         isLocal : true,
11660         reader: new Roo.data.ArrayReader({
11661                 id: config.id
11662             },
11663             Roo.data.Record.create(config.fields)
11664         ),
11665         proxy : new Roo.data.MemoryProxy(config.data)
11666     });
11667     this.load();
11668 };
11669 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11670  * Based on:
11671  * Ext JS Library 1.1.1
11672  * Copyright(c) 2006-2007, Ext JS, LLC.
11673  *
11674  * Originally Released Under LGPL - original licence link has changed is not relivant.
11675  *
11676  * Fork - LGPL
11677  * <script type="text/javascript">
11678  */
11679
11680 /**
11681 /**
11682  * @extends Roo.data.Store
11683  * @class Roo.data.JsonStore
11684  * Small helper class to make creating Stores for JSON data easier. <br/>
11685 <pre><code>
11686 var store = new Roo.data.JsonStore({
11687     url: 'get-images.php',
11688     root: 'images',
11689     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11690 });
11691 </code></pre>
11692  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11693  * JsonReader and HttpProxy (unless inline data is provided).</b>
11694  * @cfg {Array} fields An array of field definition objects, or field name strings.
11695  * @constructor
11696  * @param {Object} config
11697  */
11698 Roo.data.JsonStore = function(c){
11699     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11700         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11701         reader: new Roo.data.JsonReader(c, c.fields)
11702     }));
11703 };
11704 Roo.extend(Roo.data.JsonStore, 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 Roo.data.Field = function(config){
11717     if(typeof config == "string"){
11718         config = {name: config};
11719     }
11720     Roo.apply(this, config);
11721     
11722     if(!this.type){
11723         this.type = "auto";
11724     }
11725     
11726     var st = Roo.data.SortTypes;
11727     // named sortTypes are supported, here we look them up
11728     if(typeof this.sortType == "string"){
11729         this.sortType = st[this.sortType];
11730     }
11731     
11732     // set default sortType for strings and dates
11733     if(!this.sortType){
11734         switch(this.type){
11735             case "string":
11736                 this.sortType = st.asUCString;
11737                 break;
11738             case "date":
11739                 this.sortType = st.asDate;
11740                 break;
11741             default:
11742                 this.sortType = st.none;
11743         }
11744     }
11745
11746     // define once
11747     var stripRe = /[\$,%]/g;
11748
11749     // prebuilt conversion function for this field, instead of
11750     // switching every time we're reading a value
11751     if(!this.convert){
11752         var cv, dateFormat = this.dateFormat;
11753         switch(this.type){
11754             case "":
11755             case "auto":
11756             case undefined:
11757                 cv = function(v){ return v; };
11758                 break;
11759             case "string":
11760                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11761                 break;
11762             case "int":
11763                 cv = function(v){
11764                     return v !== undefined && v !== null && v !== '' ?
11765                            parseInt(String(v).replace(stripRe, ""), 10) : '';
11766                     };
11767                 break;
11768             case "float":
11769                 cv = function(v){
11770                     return v !== undefined && v !== null && v !== '' ?
11771                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
11772                     };
11773                 break;
11774             case "bool":
11775             case "boolean":
11776                 cv = function(v){ return v === true || v === "true" || v == 1; };
11777                 break;
11778             case "date":
11779                 cv = function(v){
11780                     if(!v){
11781                         return '';
11782                     }
11783                     if(v instanceof Date){
11784                         return v;
11785                     }
11786                     if(dateFormat){
11787                         if(dateFormat == "timestamp"){
11788                             return new Date(v*1000);
11789                         }
11790                         return Date.parseDate(v, dateFormat);
11791                     }
11792                     var parsed = Date.parse(v);
11793                     return parsed ? new Date(parsed) : null;
11794                 };
11795              break;
11796             
11797         }
11798         this.convert = cv;
11799     }
11800 };
11801
11802 Roo.data.Field.prototype = {
11803     dateFormat: null,
11804     defaultValue: "",
11805     mapping: null,
11806     sortType : null,
11807     sortDir : "ASC"
11808 };/*
11809  * Based on:
11810  * Ext JS Library 1.1.1
11811  * Copyright(c) 2006-2007, Ext JS, LLC.
11812  *
11813  * Originally Released Under LGPL - original licence link has changed is not relivant.
11814  *
11815  * Fork - LGPL
11816  * <script type="text/javascript">
11817  */
11818  
11819 // Base class for reading structured data from a data source.  This class is intended to be
11820 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11821
11822 /**
11823  * @class Roo.data.DataReader
11824  * Base class for reading structured data from a data source.  This class is intended to be
11825  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11826  */
11827
11828 Roo.data.DataReader = function(meta, recordType){
11829     
11830     this.meta = meta;
11831     
11832     this.recordType = recordType instanceof Array ? 
11833         Roo.data.Record.create(recordType) : recordType;
11834 };
11835
11836 Roo.data.DataReader.prototype = {
11837      /**
11838      * Create an empty record
11839      * @param {Object} data (optional) - overlay some values
11840      * @return {Roo.data.Record} record created.
11841      */
11842     newRow :  function(d) {
11843         var da =  {};
11844         this.recordType.prototype.fields.each(function(c) {
11845             switch( c.type) {
11846                 case 'int' : da[c.name] = 0; break;
11847                 case 'date' : da[c.name] = new Date(); break;
11848                 case 'float' : da[c.name] = 0.0; break;
11849                 case 'boolean' : da[c.name] = false; break;
11850                 default : da[c.name] = ""; break;
11851             }
11852             
11853         });
11854         return new this.recordType(Roo.apply(da, d));
11855     }
11856     
11857 };/*
11858  * Based on:
11859  * Ext JS Library 1.1.1
11860  * Copyright(c) 2006-2007, Ext JS, LLC.
11861  *
11862  * Originally Released Under LGPL - original licence link has changed is not relivant.
11863  *
11864  * Fork - LGPL
11865  * <script type="text/javascript">
11866  */
11867
11868 /**
11869  * @class Roo.data.DataProxy
11870  * @extends Roo.data.Observable
11871  * This class is an abstract base class for implementations which provide retrieval of
11872  * unformatted data objects.<br>
11873  * <p>
11874  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11875  * (of the appropriate type which knows how to parse the data object) to provide a block of
11876  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11877  * <p>
11878  * Custom implementations must implement the load method as described in
11879  * {@link Roo.data.HttpProxy#load}.
11880  */
11881 Roo.data.DataProxy = function(){
11882     this.addEvents({
11883         /**
11884          * @event beforeload
11885          * Fires before a network request is made to retrieve a data object.
11886          * @param {Object} This DataProxy object.
11887          * @param {Object} params The params parameter to the load function.
11888          */
11889         beforeload : true,
11890         /**
11891          * @event load
11892          * Fires before the load method's callback is called.
11893          * @param {Object} This DataProxy object.
11894          * @param {Object} o The data object.
11895          * @param {Object} arg The callback argument object passed to the load function.
11896          */
11897         load : true,
11898         /**
11899          * @event loadexception
11900          * Fires if an Exception occurs during data retrieval.
11901          * @param {Object} This DataProxy object.
11902          * @param {Object} o The data object.
11903          * @param {Object} arg The callback argument object passed to the load function.
11904          * @param {Object} e The Exception.
11905          */
11906         loadexception : true
11907     });
11908     Roo.data.DataProxy.superclass.constructor.call(this);
11909 };
11910
11911 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11912
11913     /**
11914      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11915      */
11916 /*
11917  * Based on:
11918  * Ext JS Library 1.1.1
11919  * Copyright(c) 2006-2007, Ext JS, LLC.
11920  *
11921  * Originally Released Under LGPL - original licence link has changed is not relivant.
11922  *
11923  * Fork - LGPL
11924  * <script type="text/javascript">
11925  */
11926 /**
11927  * @class Roo.data.MemoryProxy
11928  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11929  * to the Reader when its load method is called.
11930  * @constructor
11931  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11932  */
11933 Roo.data.MemoryProxy = function(data){
11934     if (data.data) {
11935         data = data.data;
11936     }
11937     Roo.data.MemoryProxy.superclass.constructor.call(this);
11938     this.data = data;
11939 };
11940
11941 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11942     
11943     /**
11944      * Load data from the requested source (in this case an in-memory
11945      * data object passed to the constructor), read the data object into
11946      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11947      * process that block using the passed callback.
11948      * @param {Object} params This parameter is not used by the MemoryProxy class.
11949      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11950      * object into a block of Roo.data.Records.
11951      * @param {Function} callback The function into which to pass the block of Roo.data.records.
11952      * The function must be passed <ul>
11953      * <li>The Record block object</li>
11954      * <li>The "arg" argument from the load function</li>
11955      * <li>A boolean success indicator</li>
11956      * </ul>
11957      * @param {Object} scope The scope in which to call the callback
11958      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11959      */
11960     load : function(params, reader, callback, scope, arg){
11961         params = params || {};
11962         var result;
11963         try {
11964             result = reader.readRecords(this.data);
11965         }catch(e){
11966             this.fireEvent("loadexception", this, arg, null, e);
11967             callback.call(scope, null, arg, false);
11968             return;
11969         }
11970         callback.call(scope, result, arg, true);
11971     },
11972     
11973     // private
11974     update : function(params, records){
11975         
11976     }
11977 });/*
11978  * Based on:
11979  * Ext JS Library 1.1.1
11980  * Copyright(c) 2006-2007, Ext JS, LLC.
11981  *
11982  * Originally Released Under LGPL - original licence link has changed is not relivant.
11983  *
11984  * Fork - LGPL
11985  * <script type="text/javascript">
11986  */
11987 /**
11988  * @class Roo.data.HttpProxy
11989  * @extends Roo.data.DataProxy
11990  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11991  * configured to reference a certain URL.<br><br>
11992  * <p>
11993  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
11994  * from which the running page was served.<br><br>
11995  * <p>
11996  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
11997  * <p>
11998  * Be aware that to enable the browser to parse an XML document, the server must set
11999  * the Content-Type header in the HTTP response to "text/xml".
12000  * @constructor
12001  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12002  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
12003  * will be used to make the request.
12004  */
12005 Roo.data.HttpProxy = function(conn){
12006     Roo.data.HttpProxy.superclass.constructor.call(this);
12007     // is conn a conn config or a real conn?
12008     this.conn = conn;
12009     this.useAjax = !conn || !conn.events;
12010   
12011 };
12012
12013 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12014     // thse are take from connection...
12015     
12016     /**
12017      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12018      */
12019     /**
12020      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12021      * extra parameters to each request made by this object. (defaults to undefined)
12022      */
12023     /**
12024      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12025      *  to each request made by this object. (defaults to undefined)
12026      */
12027     /**
12028      * @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)
12029      */
12030     /**
12031      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12032      */
12033      /**
12034      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12035      * @type Boolean
12036      */
12037   
12038
12039     /**
12040      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12041      * @type Boolean
12042      */
12043     /**
12044      * Return the {@link Roo.data.Connection} object being used by this Proxy.
12045      * @return {Connection} The Connection object. This object may be used to subscribe to events on
12046      * a finer-grained basis than the DataProxy events.
12047      */
12048     getConnection : function(){
12049         return this.useAjax ? Roo.Ajax : this.conn;
12050     },
12051
12052     /**
12053      * Load data from the configured {@link Roo.data.Connection}, read the data object into
12054      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12055      * process that block using the passed callback.
12056      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12057      * for the request to the remote server.
12058      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12059      * object into a block of Roo.data.Records.
12060      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12061      * The function must be passed <ul>
12062      * <li>The Record block object</li>
12063      * <li>The "arg" argument from the load function</li>
12064      * <li>A boolean success indicator</li>
12065      * </ul>
12066      * @param {Object} scope The scope in which to call the callback
12067      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12068      */
12069     load : function(params, reader, callback, scope, arg){
12070         if(this.fireEvent("beforeload", this, params) !== false){
12071             var  o = {
12072                 params : params || {},
12073                 request: {
12074                     callback : callback,
12075                     scope : scope,
12076                     arg : arg
12077                 },
12078                 reader: reader,
12079                 callback : this.loadResponse,
12080                 scope: this
12081             };
12082             if(this.useAjax){
12083                 Roo.applyIf(o, this.conn);
12084                 if(this.activeRequest){
12085                     Roo.Ajax.abort(this.activeRequest);
12086                 }
12087                 this.activeRequest = Roo.Ajax.request(o);
12088             }else{
12089                 this.conn.request(o);
12090             }
12091         }else{
12092             callback.call(scope||this, null, arg, false);
12093         }
12094     },
12095
12096     // private
12097     loadResponse : function(o, success, response){
12098         delete this.activeRequest;
12099         if(!success){
12100             this.fireEvent("loadexception", this, o, response);
12101             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12102             return;
12103         }
12104         var result;
12105         try {
12106             result = o.reader.read(response);
12107         }catch(e){
12108             this.fireEvent("loadexception", this, o, response, e);
12109             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12110             return;
12111         }
12112         
12113         this.fireEvent("load", this, o, o.request.arg);
12114         o.request.callback.call(o.request.scope, result, o.request.arg, true);
12115     },
12116
12117     // private
12118     update : function(dataSet){
12119
12120     },
12121
12122     // private
12123     updateResponse : function(dataSet){
12124
12125     }
12126 });/*
12127  * Based on:
12128  * Ext JS Library 1.1.1
12129  * Copyright(c) 2006-2007, Ext JS, LLC.
12130  *
12131  * Originally Released Under LGPL - original licence link has changed is not relivant.
12132  *
12133  * Fork - LGPL
12134  * <script type="text/javascript">
12135  */
12136
12137 /**
12138  * @class Roo.data.ScriptTagProxy
12139  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12140  * other than the originating domain of the running page.<br><br>
12141  * <p>
12142  * <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
12143  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12144  * <p>
12145  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12146  * source code that is used as the source inside a &lt;script> tag.<br><br>
12147  * <p>
12148  * In order for the browser to process the returned data, the server must wrap the data object
12149  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12150  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12151  * depending on whether the callback name was passed:
12152  * <p>
12153  * <pre><code>
12154 boolean scriptTag = false;
12155 String cb = request.getParameter("callback");
12156 if (cb != null) {
12157     scriptTag = true;
12158     response.setContentType("text/javascript");
12159 } else {
12160     response.setContentType("application/x-json");
12161 }
12162 Writer out = response.getWriter();
12163 if (scriptTag) {
12164     out.write(cb + "(");
12165 }
12166 out.print(dataBlock.toJsonString());
12167 if (scriptTag) {
12168     out.write(");");
12169 }
12170 </pre></code>
12171  *
12172  * @constructor
12173  * @param {Object} config A configuration object.
12174  */
12175 Roo.data.ScriptTagProxy = function(config){
12176     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12177     Roo.apply(this, config);
12178     this.head = document.getElementsByTagName("head")[0];
12179 };
12180
12181 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12182
12183 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12184     /**
12185      * @cfg {String} url The URL from which to request the data object.
12186      */
12187     /**
12188      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12189      */
12190     timeout : 30000,
12191     /**
12192      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12193      * the server the name of the callback function set up by the load call to process the returned data object.
12194      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12195      * javascript output which calls this named function passing the data object as its only parameter.
12196      */
12197     callbackParam : "callback",
12198     /**
12199      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12200      * name to the request.
12201      */
12202     nocache : true,
12203
12204     /**
12205      * Load data from the configured URL, read the data object into
12206      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12207      * process that block using the passed callback.
12208      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12209      * for the request to the remote server.
12210      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12211      * object into a block of Roo.data.Records.
12212      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12213      * The function must be passed <ul>
12214      * <li>The Record block object</li>
12215      * <li>The "arg" argument from the load function</li>
12216      * <li>A boolean success indicator</li>
12217      * </ul>
12218      * @param {Object} scope The scope in which to call the callback
12219      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12220      */
12221     load : function(params, reader, callback, scope, arg){
12222         if(this.fireEvent("beforeload", this, params) !== false){
12223
12224             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12225
12226             var url = this.url;
12227             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12228             if(this.nocache){
12229                 url += "&_dc=" + (new Date().getTime());
12230             }
12231             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12232             var trans = {
12233                 id : transId,
12234                 cb : "stcCallback"+transId,
12235                 scriptId : "stcScript"+transId,
12236                 params : params,
12237                 arg : arg,
12238                 url : url,
12239                 callback : callback,
12240                 scope : scope,
12241                 reader : reader
12242             };
12243             var conn = this;
12244
12245             window[trans.cb] = function(o){
12246                 conn.handleResponse(o, trans);
12247             };
12248
12249             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12250
12251             if(this.autoAbort !== false){
12252                 this.abort();
12253             }
12254
12255             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12256
12257             var script = document.createElement("script");
12258             script.setAttribute("src", url);
12259             script.setAttribute("type", "text/javascript");
12260             script.setAttribute("id", trans.scriptId);
12261             this.head.appendChild(script);
12262
12263             this.trans = trans;
12264         }else{
12265             callback.call(scope||this, null, arg, false);
12266         }
12267     },
12268
12269     // private
12270     isLoading : function(){
12271         return this.trans ? true : false;
12272     },
12273
12274     /**
12275      * Abort the current server request.
12276      */
12277     abort : function(){
12278         if(this.isLoading()){
12279             this.destroyTrans(this.trans);
12280         }
12281     },
12282
12283     // private
12284     destroyTrans : function(trans, isLoaded){
12285         this.head.removeChild(document.getElementById(trans.scriptId));
12286         clearTimeout(trans.timeoutId);
12287         if(isLoaded){
12288             window[trans.cb] = undefined;
12289             try{
12290                 delete window[trans.cb];
12291             }catch(e){}
12292         }else{
12293             // if hasn't been loaded, wait for load to remove it to prevent script error
12294             window[trans.cb] = function(){
12295                 window[trans.cb] = undefined;
12296                 try{
12297                     delete window[trans.cb];
12298                 }catch(e){}
12299             };
12300         }
12301     },
12302
12303     // private
12304     handleResponse : function(o, trans){
12305         this.trans = false;
12306         this.destroyTrans(trans, true);
12307         var result;
12308         try {
12309             result = trans.reader.readRecords(o);
12310         }catch(e){
12311             this.fireEvent("loadexception", this, o, trans.arg, e);
12312             trans.callback.call(trans.scope||window, null, trans.arg, false);
12313             return;
12314         }
12315         this.fireEvent("load", this, o, trans.arg);
12316         trans.callback.call(trans.scope||window, result, trans.arg, true);
12317     },
12318
12319     // private
12320     handleFailure : function(trans){
12321         this.trans = false;
12322         this.destroyTrans(trans, false);
12323         this.fireEvent("loadexception", this, null, trans.arg);
12324         trans.callback.call(trans.scope||window, null, trans.arg, false);
12325     }
12326 });/*
12327  * Based on:
12328  * Ext JS Library 1.1.1
12329  * Copyright(c) 2006-2007, Ext JS, LLC.
12330  *
12331  * Originally Released Under LGPL - original licence link has changed is not relivant.
12332  *
12333  * Fork - LGPL
12334  * <script type="text/javascript">
12335  */
12336
12337 /**
12338  * @class Roo.data.JsonReader
12339  * @extends Roo.data.DataReader
12340  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12341  * based on mappings in a provided Roo.data.Record constructor.
12342  * 
12343  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12344  * in the reply previously. 
12345  * 
12346  * <p>
12347  * Example code:
12348  * <pre><code>
12349 var RecordDef = Roo.data.Record.create([
12350     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
12351     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
12352 ]);
12353 var myReader = new Roo.data.JsonReader({
12354     totalProperty: "results",    // The property which contains the total dataset size (optional)
12355     root: "rows",                // The property which contains an Array of row objects
12356     id: "id"                     // The property within each row object that provides an ID for the record (optional)
12357 }, RecordDef);
12358 </code></pre>
12359  * <p>
12360  * This would consume a JSON file like this:
12361  * <pre><code>
12362 { 'results': 2, 'rows': [
12363     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12364     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12365 }
12366 </code></pre>
12367  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12368  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12369  * paged from the remote server.
12370  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12371  * @cfg {String} root name of the property which contains the Array of row objects.
12372  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12373  * @cfg {Array} fields Array of field definition objects
12374  * @constructor
12375  * Create a new JsonReader
12376  * @param {Object} meta Metadata configuration options
12377  * @param {Object} recordType Either an Array of field definition objects,
12378  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12379  */
12380 Roo.data.JsonReader = function(meta, recordType){
12381     
12382     meta = meta || {};
12383     // set some defaults:
12384     Roo.applyIf(meta, {
12385         totalProperty: 'total',
12386         successProperty : 'success',
12387         root : 'data',
12388         id : 'id'
12389     });
12390     
12391     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12392 };
12393 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12394     
12395     /**
12396      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
12397      * Used by Store query builder to append _requestMeta to params.
12398      * 
12399      */
12400     metaFromRemote : false,
12401     /**
12402      * This method is only used by a DataProxy which has retrieved data from a remote server.
12403      * @param {Object} response The XHR object which contains the JSON data in its responseText.
12404      * @return {Object} data A data block which is used by an Roo.data.Store object as
12405      * a cache of Roo.data.Records.
12406      */
12407     read : function(response){
12408         var json = response.responseText;
12409        
12410         var o = /* eval:var:o */ eval("("+json+")");
12411         if(!o) {
12412             throw {message: "JsonReader.read: Json object not found"};
12413         }
12414         
12415         if(o.metaData){
12416             
12417             delete this.ef;
12418             this.metaFromRemote = true;
12419             this.meta = o.metaData;
12420             this.recordType = Roo.data.Record.create(o.metaData.fields);
12421             this.onMetaChange(this.meta, this.recordType, o);
12422         }
12423         return this.readRecords(o);
12424     },
12425
12426     // private function a store will implement
12427     onMetaChange : function(meta, recordType, o){
12428
12429     },
12430
12431     /**
12432          * @ignore
12433          */
12434     simpleAccess: function(obj, subsc) {
12435         return obj[subsc];
12436     },
12437
12438         /**
12439          * @ignore
12440          */
12441     getJsonAccessor: function(){
12442         var re = /[\[\.]/;
12443         return function(expr) {
12444             try {
12445                 return(re.test(expr))
12446                     ? new Function("obj", "return obj." + expr)
12447                     : function(obj){
12448                         return obj[expr];
12449                     };
12450             } catch(e){}
12451             return Roo.emptyFn;
12452         };
12453     }(),
12454
12455     /**
12456      * Create a data block containing Roo.data.Records from an XML document.
12457      * @param {Object} o An object which contains an Array of row objects in the property specified
12458      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12459      * which contains the total size of the dataset.
12460      * @return {Object} data A data block which is used by an Roo.data.Store object as
12461      * a cache of Roo.data.Records.
12462      */
12463     readRecords : function(o){
12464         /**
12465          * After any data loads, the raw JSON data is available for further custom processing.
12466          * @type Object
12467          */
12468         this.o = o;
12469         var s = this.meta, Record = this.recordType,
12470             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12471
12472 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
12473         if (!this.ef) {
12474             if(s.totalProperty) {
12475                     this.getTotal = this.getJsonAccessor(s.totalProperty);
12476                 }
12477                 if(s.successProperty) {
12478                     this.getSuccess = this.getJsonAccessor(s.successProperty);
12479                 }
12480                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12481                 if (s.id) {
12482                         var g = this.getJsonAccessor(s.id);
12483                         this.getId = function(rec) {
12484                                 var r = g(rec);  
12485                                 return (r === undefined || r === "") ? null : r;
12486                         };
12487                 } else {
12488                         this.getId = function(){return null;};
12489                 }
12490             this.ef = [];
12491             for(var jj = 0; jj < fl; jj++){
12492                 f = fi[jj];
12493                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12494                 this.ef[jj] = this.getJsonAccessor(map);
12495             }
12496         }
12497
12498         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12499         if(s.totalProperty){
12500             var vt = parseInt(this.getTotal(o), 10);
12501             if(!isNaN(vt)){
12502                 totalRecords = vt;
12503             }
12504         }
12505         if(s.successProperty){
12506             var vs = this.getSuccess(o);
12507             if(vs === false || vs === 'false'){
12508                 success = false;
12509             }
12510         }
12511         var records = [];
12512         for(var i = 0; i < c; i++){
12513                 var n = root[i];
12514             var values = {};
12515             var id = this.getId(n);
12516             for(var j = 0; j < fl; j++){
12517                 f = fi[j];
12518             var v = this.ef[j](n);
12519             if (!f.convert) {
12520                 Roo.log('missing convert for ' + f.name);
12521                 Roo.log(f);
12522                 continue;
12523             }
12524             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12525             }
12526             var record = new Record(values, id);
12527             record.json = n;
12528             records[i] = record;
12529         }
12530         return {
12531             raw : o,
12532             success : success,
12533             records : records,
12534             totalRecords : totalRecords
12535         };
12536     }
12537 });/*
12538  * Based on:
12539  * Ext JS Library 1.1.1
12540  * Copyright(c) 2006-2007, Ext JS, LLC.
12541  *
12542  * Originally Released Under LGPL - original licence link has changed is not relivant.
12543  *
12544  * Fork - LGPL
12545  * <script type="text/javascript">
12546  */
12547
12548 /**
12549  * @class Roo.data.ArrayReader
12550  * @extends Roo.data.DataReader
12551  * Data reader class to create an Array of Roo.data.Record objects from an Array.
12552  * Each element of that Array represents a row of data fields. The
12553  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12554  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12555  * <p>
12556  * Example code:.
12557  * <pre><code>
12558 var RecordDef = Roo.data.Record.create([
12559     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
12560     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
12561 ]);
12562 var myReader = new Roo.data.ArrayReader({
12563     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
12564 }, RecordDef);
12565 </code></pre>
12566  * <p>
12567  * This would consume an Array like this:
12568  * <pre><code>
12569 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12570   </code></pre>
12571  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12572  * @constructor
12573  * Create a new JsonReader
12574  * @param {Object} meta Metadata configuration options.
12575  * @param {Object} recordType Either an Array of field definition objects
12576  * as specified to {@link Roo.data.Record#create},
12577  * or an {@link Roo.data.Record} object
12578  * created using {@link Roo.data.Record#create}.
12579  */
12580 Roo.data.ArrayReader = function(meta, recordType){
12581     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12582 };
12583
12584 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12585     /**
12586      * Create a data block containing Roo.data.Records from an XML document.
12587      * @param {Object} o An Array of row objects which represents the dataset.
12588      * @return {Object} data A data block which is used by an Roo.data.Store object as
12589      * a cache of Roo.data.Records.
12590      */
12591     readRecords : function(o){
12592         var sid = this.meta ? this.meta.id : null;
12593         var recordType = this.recordType, fields = recordType.prototype.fields;
12594         var records = [];
12595         var root = o;
12596             for(var i = 0; i < root.length; i++){
12597                     var n = root[i];
12598                 var values = {};
12599                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12600                 for(var j = 0, jlen = fields.length; j < jlen; j++){
12601                 var f = fields.items[j];
12602                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12603                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12604                 v = f.convert(v);
12605                 values[f.name] = v;
12606             }
12607                 var record = new recordType(values, id);
12608                 record.json = n;
12609                 records[records.length] = record;
12610             }
12611             return {
12612                 records : records,
12613                 totalRecords : records.length
12614             };
12615     }
12616 });/*
12617  * - LGPL
12618  * * 
12619  */
12620
12621 /**
12622  * @class Roo.bootstrap.ComboBox
12623  * @extends Roo.bootstrap.TriggerField
12624  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12625  * @cfg {Boolean} append (true|false) default false
12626  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12627  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12628  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12629  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12630  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12631  * @cfg {Boolean} animate default true
12632  * @cfg {Boolean} emptyResultText only for touch device
12633  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12634  * @cfg {String} emptyTitle default ''
12635  * @constructor
12636  * Create a new ComboBox.
12637  * @param {Object} config Configuration options
12638  */
12639 Roo.bootstrap.ComboBox = function(config){
12640     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12641     this.addEvents({
12642         /**
12643          * @event expand
12644          * Fires when the dropdown list is expanded
12645         * @param {Roo.bootstrap.ComboBox} combo This combo box
12646         */
12647         'expand' : true,
12648         /**
12649          * @event collapse
12650          * Fires when the dropdown list is collapsed
12651         * @param {Roo.bootstrap.ComboBox} combo This combo box
12652         */
12653         'collapse' : true,
12654         /**
12655          * @event beforeselect
12656          * Fires before a list item is selected. Return false to cancel the selection.
12657         * @param {Roo.bootstrap.ComboBox} combo This combo box
12658         * @param {Roo.data.Record} record The data record returned from the underlying store
12659         * @param {Number} index The index of the selected item in the dropdown list
12660         */
12661         'beforeselect' : true,
12662         /**
12663          * @event select
12664          * Fires when a list item is selected
12665         * @param {Roo.bootstrap.ComboBox} combo This combo box
12666         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12667         * @param {Number} index The index of the selected item in the dropdown list
12668         */
12669         'select' : true,
12670         /**
12671          * @event beforequery
12672          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12673          * The event object passed has these properties:
12674         * @param {Roo.bootstrap.ComboBox} combo This combo box
12675         * @param {String} query The query
12676         * @param {Boolean} forceAll true to force "all" query
12677         * @param {Boolean} cancel true to cancel the query
12678         * @param {Object} e The query event object
12679         */
12680         'beforequery': true,
12681          /**
12682          * @event add
12683          * Fires when the 'add' icon is pressed (add a listener to enable add button)
12684         * @param {Roo.bootstrap.ComboBox} combo This combo box
12685         */
12686         'add' : true,
12687         /**
12688          * @event edit
12689          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12690         * @param {Roo.bootstrap.ComboBox} combo This combo box
12691         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12692         */
12693         'edit' : true,
12694         /**
12695          * @event remove
12696          * Fires when the remove value from the combobox array
12697         * @param {Roo.bootstrap.ComboBox} combo This combo box
12698         */
12699         'remove' : true,
12700         /**
12701          * @event afterremove
12702          * Fires when the remove value from the combobox array
12703         * @param {Roo.bootstrap.ComboBox} combo This combo box
12704         */
12705         'afterremove' : true,
12706         /**
12707          * @event specialfilter
12708          * Fires when specialfilter
12709             * @param {Roo.bootstrap.ComboBox} combo This combo box
12710             */
12711         'specialfilter' : true,
12712         /**
12713          * @event tick
12714          * Fires when tick the element
12715             * @param {Roo.bootstrap.ComboBox} combo This combo box
12716             */
12717         'tick' : true,
12718         /**
12719          * @event touchviewdisplay
12720          * Fires when touch view require special display (default is using displayField)
12721             * @param {Roo.bootstrap.ComboBox} combo This combo box
12722             * @param {Object} cfg set html .
12723             */
12724         'touchviewdisplay' : true
12725         
12726     });
12727     
12728     this.item = [];
12729     this.tickItems = [];
12730     
12731     this.selectedIndex = -1;
12732     if(this.mode == 'local'){
12733         if(config.queryDelay === undefined){
12734             this.queryDelay = 10;
12735         }
12736         if(config.minChars === undefined){
12737             this.minChars = 0;
12738         }
12739     }
12740 };
12741
12742 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12743      
12744     /**
12745      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12746      * rendering into an Roo.Editor, defaults to false)
12747      */
12748     /**
12749      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12750      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12751      */
12752     /**
12753      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12754      */
12755     /**
12756      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12757      * the dropdown list (defaults to undefined, with no header element)
12758      */
12759
12760      /**
12761      * @cfg {String/Roo.Template} tpl The template to use to render the output
12762      */
12763      
12764      /**
12765      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12766      */
12767     listWidth: undefined,
12768     /**
12769      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12770      * mode = 'remote' or 'text' if mode = 'local')
12771      */
12772     displayField: undefined,
12773     
12774     /**
12775      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12776      * mode = 'remote' or 'value' if mode = 'local'). 
12777      * Note: use of a valueField requires the user make a selection
12778      * in order for a value to be mapped.
12779      */
12780     valueField: undefined,
12781     /**
12782      * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12783      */
12784     modalTitle : '',
12785     
12786     /**
12787      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12788      * field's data value (defaults to the underlying DOM element's name)
12789      */
12790     hiddenName: undefined,
12791     /**
12792      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12793      */
12794     listClass: '',
12795     /**
12796      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12797      */
12798     selectedClass: 'active',
12799     
12800     /**
12801      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12802      */
12803     shadow:'sides',
12804     /**
12805      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12806      * anchor positions (defaults to 'tl-bl')
12807      */
12808     listAlign: 'tl-bl?',
12809     /**
12810      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12811      */
12812     maxHeight: 300,
12813     /**
12814      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
12815      * query specified by the allQuery config option (defaults to 'query')
12816      */
12817     triggerAction: 'query',
12818     /**
12819      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12820      * (defaults to 4, does not apply if editable = false)
12821      */
12822     minChars : 4,
12823     /**
12824      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12825      * delay (typeAheadDelay) if it matches a known value (defaults to false)
12826      */
12827     typeAhead: false,
12828     /**
12829      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12830      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12831      */
12832     queryDelay: 500,
12833     /**
12834      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12835      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
12836      */
12837     pageSize: 0,
12838     /**
12839      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
12840      * when editable = true (defaults to false)
12841      */
12842     selectOnFocus:false,
12843     /**
12844      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12845      */
12846     queryParam: 'query',
12847     /**
12848      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
12849      * when mode = 'remote' (defaults to 'Loading...')
12850      */
12851     loadingText: 'Loading...',
12852     /**
12853      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12854      */
12855     resizable: false,
12856     /**
12857      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12858      */
12859     handleHeight : 8,
12860     /**
12861      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12862      * traditional select (defaults to true)
12863      */
12864     editable: true,
12865     /**
12866      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12867      */
12868     allQuery: '',
12869     /**
12870      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12871      */
12872     mode: 'remote',
12873     /**
12874      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12875      * listWidth has a higher value)
12876      */
12877     minListWidth : 70,
12878     /**
12879      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12880      * allow the user to set arbitrary text into the field (defaults to false)
12881      */
12882     forceSelection:false,
12883     /**
12884      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12885      * if typeAhead = true (defaults to 250)
12886      */
12887     typeAheadDelay : 250,
12888     /**
12889      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12890      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12891      */
12892     valueNotFoundText : undefined,
12893     /**
12894      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12895      */
12896     blockFocus : false,
12897     
12898     /**
12899      * @cfg {Boolean} disableClear Disable showing of clear button.
12900      */
12901     disableClear : false,
12902     /**
12903      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
12904      */
12905     alwaysQuery : false,
12906     
12907     /**
12908      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
12909      */
12910     multiple : false,
12911     
12912     /**
12913      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12914      */
12915     invalidClass : "has-warning",
12916     
12917     /**
12918      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12919      */
12920     validClass : "has-success",
12921     
12922     /**
12923      * @cfg {Boolean} specialFilter (true|false) special filter default false
12924      */
12925     specialFilter : false,
12926     
12927     /**
12928      * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12929      */
12930     mobileTouchView : true,
12931     
12932     /**
12933      * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12934      */
12935     useNativeIOS : false,
12936     
12937     ios_options : false,
12938     
12939     //private
12940     addicon : false,
12941     editicon: false,
12942     
12943     page: 0,
12944     hasQuery: false,
12945     append: false,
12946     loadNext: false,
12947     autoFocus : true,
12948     tickable : false,
12949     btnPosition : 'right',
12950     triggerList : true,
12951     showToggleBtn : true,
12952     animate : true,
12953     emptyResultText: 'Empty',
12954     triggerText : 'Select',
12955     emptyTitle : '',
12956     
12957     // element that contains real text value.. (when hidden is used..)
12958     
12959     getAutoCreate : function()
12960     {   
12961         var cfg = false;
12962         //render
12963         /*
12964          * Render classic select for iso
12965          */
12966         
12967         if(Roo.isIOS && this.useNativeIOS){
12968             cfg = this.getAutoCreateNativeIOS();
12969             return cfg;
12970         }
12971         
12972         /*
12973          * Touch Devices
12974          */
12975         
12976         if(Roo.isTouch && this.mobileTouchView){
12977             cfg = this.getAutoCreateTouchView();
12978             return cfg;;
12979         }
12980         
12981         /*
12982          *  Normal ComboBox
12983          */
12984         if(!this.tickable){
12985             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12986             return cfg;
12987         }
12988         
12989         /*
12990          *  ComboBox with tickable selections
12991          */
12992              
12993         var align = this.labelAlign || this.parentLabelAlign();
12994         
12995         cfg = {
12996             cls : 'form-group roo-combobox-tickable' //input-group
12997         };
12998         
12999         var btn_text_select = '';
13000         var btn_text_done = '';
13001         var btn_text_cancel = '';
13002         
13003         if (this.btn_text_show) {
13004             btn_text_select = 'Select';
13005             btn_text_done = 'Done';
13006             btn_text_cancel = 'Cancel'; 
13007         }
13008         
13009         var buttons = {
13010             tag : 'div',
13011             cls : 'tickable-buttons',
13012             cn : [
13013                 {
13014                     tag : 'button',
13015                     type : 'button',
13016                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13017                     //html : this.triggerText
13018                     html: btn_text_select
13019                 },
13020                 {
13021                     tag : 'button',
13022                     type : 'button',
13023                     name : 'ok',
13024                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13025                     //html : 'Done'
13026                     html: btn_text_done
13027                 },
13028                 {
13029                     tag : 'button',
13030                     type : 'button',
13031                     name : 'cancel',
13032                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13033                     //html : 'Cancel'
13034                     html: btn_text_cancel
13035                 }
13036             ]
13037         };
13038         
13039         if(this.editable){
13040             buttons.cn.unshift({
13041                 tag: 'input',
13042                 cls: 'roo-select2-search-field-input'
13043             });
13044         }
13045         
13046         var _this = this;
13047         
13048         Roo.each(buttons.cn, function(c){
13049             if (_this.size) {
13050                 c.cls += ' btn-' + _this.size;
13051             }
13052
13053             if (_this.disabled) {
13054                 c.disabled = true;
13055             }
13056         });
13057         
13058         var box = {
13059             tag: 'div',
13060             cn: [
13061                 {
13062                     tag: 'input',
13063                     type : 'hidden',
13064                     cls: 'form-hidden-field'
13065                 },
13066                 {
13067                     tag: 'ul',
13068                     cls: 'roo-select2-choices',
13069                     cn:[
13070                         {
13071                             tag: 'li',
13072                             cls: 'roo-select2-search-field',
13073                             cn: [
13074                                 buttons
13075                             ]
13076                         }
13077                     ]
13078                 }
13079             ]
13080         };
13081         
13082         var combobox = {
13083             cls: 'roo-select2-container input-group roo-select2-container-multi',
13084             cn: [
13085                 box
13086 //                {
13087 //                    tag: 'ul',
13088 //                    cls: 'typeahead typeahead-long dropdown-menu',
13089 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
13090 //                }
13091             ]
13092         };
13093         
13094         if(this.hasFeedback && !this.allowBlank){
13095             
13096             var feedback = {
13097                 tag: 'span',
13098                 cls: 'glyphicon form-control-feedback'
13099             };
13100
13101             combobox.cn.push(feedback);
13102         }
13103         
13104         
13105         if (align ==='left' && this.fieldLabel.length) {
13106             
13107             cfg.cls += ' roo-form-group-label-left';
13108             
13109             cfg.cn = [
13110                 {
13111                     tag : 'i',
13112                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13113                     tooltip : 'This field is required'
13114                 },
13115                 {
13116                     tag: 'label',
13117                     'for' :  id,
13118                     cls : 'control-label',
13119                     html : this.fieldLabel
13120
13121                 },
13122                 {
13123                     cls : "", 
13124                     cn: [
13125                         combobox
13126                     ]
13127                 }
13128
13129             ];
13130             
13131             var labelCfg = cfg.cn[1];
13132             var contentCfg = cfg.cn[2];
13133             
13134
13135             if(this.indicatorpos == 'right'){
13136                 
13137                 cfg.cn = [
13138                     {
13139                         tag: 'label',
13140                         'for' :  id,
13141                         cls : 'control-label',
13142                         cn : [
13143                             {
13144                                 tag : 'span',
13145                                 html : this.fieldLabel
13146                             },
13147                             {
13148                                 tag : 'i',
13149                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13150                                 tooltip : 'This field is required'
13151                             }
13152                         ]
13153                     },
13154                     {
13155                         cls : "",
13156                         cn: [
13157                             combobox
13158                         ]
13159                     }
13160
13161                 ];
13162                 
13163                 
13164                 
13165                 labelCfg = cfg.cn[0];
13166                 contentCfg = cfg.cn[1];
13167             
13168             }
13169             
13170             if(this.labelWidth > 12){
13171                 labelCfg.style = "width: " + this.labelWidth + 'px';
13172             }
13173             
13174             if(this.labelWidth < 13 && this.labelmd == 0){
13175                 this.labelmd = this.labelWidth;
13176             }
13177             
13178             if(this.labellg > 0){
13179                 labelCfg.cls += ' col-lg-' + this.labellg;
13180                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13181             }
13182             
13183             if(this.labelmd > 0){
13184                 labelCfg.cls += ' col-md-' + this.labelmd;
13185                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13186             }
13187             
13188             if(this.labelsm > 0){
13189                 labelCfg.cls += ' col-sm-' + this.labelsm;
13190                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13191             }
13192             
13193             if(this.labelxs > 0){
13194                 labelCfg.cls += ' col-xs-' + this.labelxs;
13195                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13196             }
13197                 
13198                 
13199         } else if ( this.fieldLabel.length) {
13200 //                Roo.log(" label");
13201                  cfg.cn = [
13202                     {
13203                         tag : 'i',
13204                         cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13205                         tooltip : 'This field is required'
13206                     },
13207                     {
13208                         tag: 'label',
13209                         //cls : 'input-group-addon',
13210                         html : this.fieldLabel
13211                     },
13212                     combobox
13213                 ];
13214                 
13215                 if(this.indicatorpos == 'right'){
13216                     cfg.cn = [
13217                         {
13218                             tag: 'label',
13219                             //cls : 'input-group-addon',
13220                             html : this.fieldLabel
13221                         },
13222                         {
13223                             tag : 'i',
13224                             cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13225                             tooltip : 'This field is required'
13226                         },
13227                         combobox
13228                     ];
13229                     
13230                 }
13231
13232         } else {
13233             
13234 //                Roo.log(" no label && no align");
13235                 cfg = combobox
13236                      
13237                 
13238         }
13239          
13240         var settings=this;
13241         ['xs','sm','md','lg'].map(function(size){
13242             if (settings[size]) {
13243                 cfg.cls += ' col-' + size + '-' + settings[size];
13244             }
13245         });
13246         
13247         return cfg;
13248         
13249     },
13250     
13251     _initEventsCalled : false,
13252     
13253     // private
13254     initEvents: function()
13255     {   
13256         if (this._initEventsCalled) { // as we call render... prevent looping...
13257             return;
13258         }
13259         this._initEventsCalled = true;
13260         
13261         if (!this.store) {
13262             throw "can not find store for combo";
13263         }
13264         
13265         this.indicator = this.indicatorEl();
13266         
13267         this.store = Roo.factory(this.store, Roo.data);
13268         this.store.parent = this;
13269         
13270         // if we are building from html. then this element is so complex, that we can not really
13271         // use the rendered HTML.
13272         // so we have to trash and replace the previous code.
13273         if (Roo.XComponent.build_from_html) {
13274             // remove this element....
13275             var e = this.el.dom, k=0;
13276             while (e ) { e = e.previousSibling;  ++k;}
13277
13278             this.el.remove();
13279             
13280             this.el=false;
13281             this.rendered = false;
13282             
13283             this.render(this.parent().getChildContainer(true), k);
13284         }
13285         
13286         if(Roo.isIOS && this.useNativeIOS){
13287             this.initIOSView();
13288             return;
13289         }
13290         
13291         /*
13292          * Touch Devices
13293          */
13294         
13295         if(Roo.isTouch && this.mobileTouchView){
13296             this.initTouchView();
13297             return;
13298         }
13299         
13300         if(this.tickable){
13301             this.initTickableEvents();
13302             return;
13303         }
13304         
13305         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13306         
13307         if(this.hiddenName){
13308             
13309             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13310             
13311             this.hiddenField.dom.value =
13312                 this.hiddenValue !== undefined ? this.hiddenValue :
13313                 this.value !== undefined ? this.value : '';
13314
13315             // prevent input submission
13316             this.el.dom.removeAttribute('name');
13317             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13318              
13319              
13320         }
13321         //if(Roo.isGecko){
13322         //    this.el.dom.setAttribute('autocomplete', 'off');
13323         //}
13324         
13325         var cls = 'x-combo-list';
13326         
13327         //this.list = new Roo.Layer({
13328         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13329         //});
13330         
13331         var _this = this;
13332         
13333         (function(){
13334             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13335             _this.list.setWidth(lw);
13336         }).defer(100);
13337         
13338         this.list.on('mouseover', this.onViewOver, this);
13339         this.list.on('mousemove', this.onViewMove, this);
13340         this.list.on('scroll', this.onViewScroll, this);
13341         
13342         /*
13343         this.list.swallowEvent('mousewheel');
13344         this.assetHeight = 0;
13345
13346         if(this.title){
13347             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13348             this.assetHeight += this.header.getHeight();
13349         }
13350
13351         this.innerList = this.list.createChild({cls:cls+'-inner'});
13352         this.innerList.on('mouseover', this.onViewOver, this);
13353         this.innerList.on('mousemove', this.onViewMove, this);
13354         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13355         
13356         if(this.allowBlank && !this.pageSize && !this.disableClear){
13357             this.footer = this.list.createChild({cls:cls+'-ft'});
13358             this.pageTb = new Roo.Toolbar(this.footer);
13359            
13360         }
13361         if(this.pageSize){
13362             this.footer = this.list.createChild({cls:cls+'-ft'});
13363             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13364                     {pageSize: this.pageSize});
13365             
13366         }
13367         
13368         if (this.pageTb && this.allowBlank && !this.disableClear) {
13369             var _this = this;
13370             this.pageTb.add(new Roo.Toolbar.Fill(), {
13371                 cls: 'x-btn-icon x-btn-clear',
13372                 text: '&#160;',
13373                 handler: function()
13374                 {
13375                     _this.collapse();
13376                     _this.clearValue();
13377                     _this.onSelect(false, -1);
13378                 }
13379             });
13380         }
13381         if (this.footer) {
13382             this.assetHeight += this.footer.getHeight();
13383         }
13384         */
13385             
13386         if(!this.tpl){
13387             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13388         }
13389
13390         this.view = new Roo.View(this.list, this.tpl, {
13391             singleSelect:true, store: this.store, selectedClass: this.selectedClass
13392         });
13393         //this.view.wrapEl.setDisplayed(false);
13394         this.view.on('click', this.onViewClick, this);
13395         
13396         
13397         this.store.on('beforeload', this.onBeforeLoad, this);
13398         this.store.on('load', this.onLoad, this);
13399         this.store.on('loadexception', this.onLoadException, this);
13400         /*
13401         if(this.resizable){
13402             this.resizer = new Roo.Resizable(this.list,  {
13403                pinned:true, handles:'se'
13404             });
13405             this.resizer.on('resize', function(r, w, h){
13406                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13407                 this.listWidth = w;
13408                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13409                 this.restrictHeight();
13410             }, this);
13411             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13412         }
13413         */
13414         if(!this.editable){
13415             this.editable = true;
13416             this.setEditable(false);
13417         }
13418         
13419         /*
13420         
13421         if (typeof(this.events.add.listeners) != 'undefined') {
13422             
13423             this.addicon = this.wrap.createChild(
13424                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
13425        
13426             this.addicon.on('click', function(e) {
13427                 this.fireEvent('add', this);
13428             }, this);
13429         }
13430         if (typeof(this.events.edit.listeners) != 'undefined') {
13431             
13432             this.editicon = this.wrap.createChild(
13433                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
13434             if (this.addicon) {
13435                 this.editicon.setStyle('margin-left', '40px');
13436             }
13437             this.editicon.on('click', function(e) {
13438                 
13439                 // we fire even  if inothing is selected..
13440                 this.fireEvent('edit', this, this.lastData );
13441                 
13442             }, this);
13443         }
13444         */
13445         
13446         this.keyNav = new Roo.KeyNav(this.inputEl(), {
13447             "up" : function(e){
13448                 this.inKeyMode = true;
13449                 this.selectPrev();
13450             },
13451
13452             "down" : function(e){
13453                 if(!this.isExpanded()){
13454                     this.onTriggerClick();
13455                 }else{
13456                     this.inKeyMode = true;
13457                     this.selectNext();
13458                 }
13459             },
13460
13461             "enter" : function(e){
13462 //                this.onViewClick();
13463                 //return true;
13464                 this.collapse();
13465                 
13466                 if(this.fireEvent("specialkey", this, e)){
13467                     this.onViewClick(false);
13468                 }
13469                 
13470                 return true;
13471             },
13472
13473             "esc" : function(e){
13474                 this.collapse();
13475             },
13476
13477             "tab" : function(e){
13478                 this.collapse();
13479                 
13480                 if(this.fireEvent("specialkey", this, e)){
13481                     this.onViewClick(false);
13482                 }
13483                 
13484                 return true;
13485             },
13486
13487             scope : this,
13488
13489             doRelay : function(foo, bar, hname){
13490                 if(hname == 'down' || this.scope.isExpanded()){
13491                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13492                 }
13493                 return true;
13494             },
13495
13496             forceKeyDown: true
13497         });
13498         
13499         
13500         this.queryDelay = Math.max(this.queryDelay || 10,
13501                 this.mode == 'local' ? 10 : 250);
13502         
13503         
13504         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13505         
13506         if(this.typeAhead){
13507             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13508         }
13509         if(this.editable !== false){
13510             this.inputEl().on("keyup", this.onKeyUp, this);
13511         }
13512         if(this.forceSelection){
13513             this.inputEl().on('blur', this.doForce, this);
13514         }
13515         
13516         if(this.multiple){
13517             this.choices = this.el.select('ul.roo-select2-choices', true).first();
13518             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13519         }
13520     },
13521     
13522     initTickableEvents: function()
13523     {   
13524         this.createList();
13525         
13526         if(this.hiddenName){
13527             
13528             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13529             
13530             this.hiddenField.dom.value =
13531                 this.hiddenValue !== undefined ? this.hiddenValue :
13532                 this.value !== undefined ? this.value : '';
13533
13534             // prevent input submission
13535             this.el.dom.removeAttribute('name');
13536             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13537              
13538              
13539         }
13540         
13541 //        this.list = this.el.select('ul.dropdown-menu',true).first();
13542         
13543         this.choices = this.el.select('ul.roo-select2-choices', true).first();
13544         this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13545         if(this.triggerList){
13546             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13547         }
13548          
13549         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13550         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13551         
13552         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13553         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13554         
13555         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13556         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13557         
13558         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13559         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13560         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13561         
13562         this.okBtn.hide();
13563         this.cancelBtn.hide();
13564         
13565         var _this = this;
13566         
13567         (function(){
13568             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13569             _this.list.setWidth(lw);
13570         }).defer(100);
13571         
13572         this.list.on('mouseover', this.onViewOver, this);
13573         this.list.on('mousemove', this.onViewMove, this);
13574         
13575         this.list.on('scroll', this.onViewScroll, this);
13576         
13577         if(!this.tpl){
13578             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>';
13579         }
13580
13581         this.view = new Roo.View(this.list, this.tpl, {
13582             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13583         });
13584         
13585         //this.view.wrapEl.setDisplayed(false);
13586         this.view.on('click', this.onViewClick, this);
13587         
13588         
13589         
13590         this.store.on('beforeload', this.onBeforeLoad, this);
13591         this.store.on('load', this.onLoad, this);
13592         this.store.on('loadexception', this.onLoadException, this);
13593         
13594         if(this.editable){
13595             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13596                 "up" : function(e){
13597                     this.inKeyMode = true;
13598                     this.selectPrev();
13599                 },
13600
13601                 "down" : function(e){
13602                     this.inKeyMode = true;
13603                     this.selectNext();
13604                 },
13605
13606                 "enter" : function(e){
13607                     if(this.fireEvent("specialkey", this, e)){
13608                         this.onViewClick(false);
13609                     }
13610                     
13611                     return true;
13612                 },
13613
13614                 "esc" : function(e){
13615                     this.onTickableFooterButtonClick(e, false, false);
13616                 },
13617
13618                 "tab" : function(e){
13619                     this.fireEvent("specialkey", this, e);
13620                     
13621                     this.onTickableFooterButtonClick(e, false, false);
13622                     
13623                     return true;
13624                 },
13625
13626                 scope : this,
13627
13628                 doRelay : function(e, fn, key){
13629                     if(this.scope.isExpanded()){
13630                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13631                     }
13632                     return true;
13633                 },
13634
13635                 forceKeyDown: true
13636             });
13637         }
13638         
13639         this.queryDelay = Math.max(this.queryDelay || 10,
13640                 this.mode == 'local' ? 10 : 250);
13641         
13642         
13643         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13644         
13645         if(this.typeAhead){
13646             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13647         }
13648         
13649         if(this.editable !== false){
13650             this.tickableInputEl().on("keyup", this.onKeyUp, this);
13651         }
13652         
13653         this.indicator = this.indicatorEl();
13654         
13655         if(this.indicator){
13656             this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13657             this.indicator.hide();
13658         }
13659         
13660     },
13661
13662     onDestroy : function(){
13663         if(this.view){
13664             this.view.setStore(null);
13665             this.view.el.removeAllListeners();
13666             this.view.el.remove();
13667             this.view.purgeListeners();
13668         }
13669         if(this.list){
13670             this.list.dom.innerHTML  = '';
13671         }
13672         
13673         if(this.store){
13674             this.store.un('beforeload', this.onBeforeLoad, this);
13675             this.store.un('load', this.onLoad, this);
13676             this.store.un('loadexception', this.onLoadException, this);
13677         }
13678         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13679     },
13680
13681     // private
13682     fireKey : function(e){
13683         if(e.isNavKeyPress() && !this.list.isVisible()){
13684             this.fireEvent("specialkey", this, e);
13685         }
13686     },
13687
13688     // private
13689     onResize: function(w, h){
13690 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13691 //        
13692 //        if(typeof w != 'number'){
13693 //            // we do not handle it!?!?
13694 //            return;
13695 //        }
13696 //        var tw = this.trigger.getWidth();
13697 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
13698 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
13699 //        var x = w - tw;
13700 //        this.inputEl().setWidth( this.adjustWidth('input', x));
13701 //            
13702 //        //this.trigger.setStyle('left', x+'px');
13703 //        
13704 //        if(this.list && this.listWidth === undefined){
13705 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13706 //            this.list.setWidth(lw);
13707 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13708 //        }
13709         
13710     
13711         
13712     },
13713
13714     /**
13715      * Allow or prevent the user from directly editing the field text.  If false is passed,
13716      * the user will only be able to select from the items defined in the dropdown list.  This method
13717      * is the runtime equivalent of setting the 'editable' config option at config time.
13718      * @param {Boolean} value True to allow the user to directly edit the field text
13719      */
13720     setEditable : function(value){
13721         if(value == this.editable){
13722             return;
13723         }
13724         this.editable = value;
13725         if(!value){
13726             this.inputEl().dom.setAttribute('readOnly', true);
13727             this.inputEl().on('mousedown', this.onTriggerClick,  this);
13728             this.inputEl().addClass('x-combo-noedit');
13729         }else{
13730             this.inputEl().dom.setAttribute('readOnly', false);
13731             this.inputEl().un('mousedown', this.onTriggerClick,  this);
13732             this.inputEl().removeClass('x-combo-noedit');
13733         }
13734     },
13735
13736     // private
13737     
13738     onBeforeLoad : function(combo,opts){
13739         if(!this.hasFocus){
13740             return;
13741         }
13742          if (!opts.add) {
13743             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13744          }
13745         this.restrictHeight();
13746         this.selectedIndex = -1;
13747     },
13748
13749     // private
13750     onLoad : function(){
13751         
13752         this.hasQuery = false;
13753         
13754         if(!this.hasFocus){
13755             return;
13756         }
13757         
13758         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13759             this.loading.hide();
13760         }
13761         
13762         if(this.store.getCount() > 0){
13763             
13764             this.expand();
13765             this.restrictHeight();
13766             if(this.lastQuery == this.allQuery){
13767                 if(this.editable && !this.tickable){
13768                     this.inputEl().dom.select();
13769                 }
13770                 
13771                 if(
13772                     !this.selectByValue(this.value, true) &&
13773                     this.autoFocus && 
13774                     (
13775                         !this.store.lastOptions ||
13776                         typeof(this.store.lastOptions.add) == 'undefined' || 
13777                         this.store.lastOptions.add != true
13778                     )
13779                 ){
13780                     this.select(0, true);
13781                 }
13782             }else{
13783                 if(this.autoFocus){
13784                     this.selectNext();
13785                 }
13786                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13787                     this.taTask.delay(this.typeAheadDelay);
13788                 }
13789             }
13790         }else{
13791             this.onEmptyResults();
13792         }
13793         
13794         //this.el.focus();
13795     },
13796     // private
13797     onLoadException : function()
13798     {
13799         this.hasQuery = false;
13800         
13801         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13802             this.loading.hide();
13803         }
13804         
13805         if(this.tickable && this.editable){
13806             return;
13807         }
13808         
13809         this.collapse();
13810         // only causes errors at present
13811         //Roo.log(this.store.reader.jsonData);
13812         //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13813             // fixme
13814             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13815         //}
13816         
13817         
13818     },
13819     // private
13820     onTypeAhead : function(){
13821         if(this.store.getCount() > 0){
13822             var r = this.store.getAt(0);
13823             var newValue = r.data[this.displayField];
13824             var len = newValue.length;
13825             var selStart = this.getRawValue().length;
13826             
13827             if(selStart != len){
13828                 this.setRawValue(newValue);
13829                 this.selectText(selStart, newValue.length);
13830             }
13831         }
13832     },
13833
13834     // private
13835     onSelect : function(record, index){
13836         
13837         if(this.fireEvent('beforeselect', this, record, index) !== false){
13838         
13839             this.setFromData(index > -1 ? record.data : false);
13840             
13841             this.collapse();
13842             this.fireEvent('select', this, record, index);
13843         }
13844     },
13845
13846     /**
13847      * Returns the currently selected field value or empty string if no value is set.
13848      * @return {String} value The selected value
13849      */
13850     getValue : function()
13851     {
13852         if(Roo.isIOS && this.useNativeIOS){
13853             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13854         }
13855         
13856         if(this.multiple){
13857             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13858         }
13859         
13860         if(this.valueField){
13861             return typeof this.value != 'undefined' ? this.value : '';
13862         }else{
13863             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13864         }
13865     },
13866     
13867     getRawValue : function()
13868     {
13869         if(Roo.isIOS && this.useNativeIOS){
13870             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13871         }
13872         
13873         var v = this.inputEl().getValue();
13874         
13875         return v;
13876     },
13877
13878     /**
13879      * Clears any text/value currently set in the field
13880      */
13881     clearValue : function(){
13882         
13883         if(this.hiddenField){
13884             this.hiddenField.dom.value = '';
13885         }
13886         this.value = '';
13887         this.setRawValue('');
13888         this.lastSelectionText = '';
13889         this.lastData = false;
13890         
13891         var close = this.closeTriggerEl();
13892         
13893         if(close){
13894             close.hide();
13895         }
13896         
13897         this.validate();
13898         
13899     },
13900
13901     /**
13902      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
13903      * will be displayed in the field.  If the value does not match the data value of an existing item,
13904      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13905      * Otherwise the field will be blank (although the value will still be set).
13906      * @param {String} value The value to match
13907      */
13908     setValue : function(v)
13909     {
13910         if(Roo.isIOS && this.useNativeIOS){
13911             this.setIOSValue(v);
13912             return;
13913         }
13914         
13915         if(this.multiple){
13916             this.syncValue();
13917             return;
13918         }
13919         
13920         var text = v;
13921         if(this.valueField){
13922             var r = this.findRecord(this.valueField, v);
13923             if(r){
13924                 text = r.data[this.displayField];
13925             }else if(this.valueNotFoundText !== undefined){
13926                 text = this.valueNotFoundText;
13927             }
13928         }
13929         this.lastSelectionText = text;
13930         if(this.hiddenField){
13931             this.hiddenField.dom.value = v;
13932         }
13933         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13934         this.value = v;
13935         
13936         var close = this.closeTriggerEl();
13937         
13938         if(close){
13939             (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13940         }
13941         
13942         this.validate();
13943     },
13944     /**
13945      * @property {Object} the last set data for the element
13946      */
13947     
13948     lastData : false,
13949     /**
13950      * Sets the value of the field based on a object which is related to the record format for the store.
13951      * @param {Object} value the value to set as. or false on reset?
13952      */
13953     setFromData : function(o){
13954         
13955         if(this.multiple){
13956             this.addItem(o);
13957             return;
13958         }
13959             
13960         var dv = ''; // display value
13961         var vv = ''; // value value..
13962         this.lastData = o;
13963         if (this.displayField) {
13964             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13965         } else {
13966             // this is an error condition!!!
13967             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
13968         }
13969         
13970         if(this.valueField){
13971             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13972         }
13973         
13974         var close = this.closeTriggerEl();
13975         
13976         if(close){
13977             if(dv.length || vv * 1 > 0){
13978                 close.show() ;
13979                 this.blockFocus=true;
13980             } else {
13981                 close.hide();
13982             }             
13983         }
13984         
13985         if(this.hiddenField){
13986             this.hiddenField.dom.value = vv;
13987             
13988             this.lastSelectionText = dv;
13989             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13990             this.value = vv;
13991             return;
13992         }
13993         // no hidden field.. - we store the value in 'value', but still display
13994         // display field!!!!
13995         this.lastSelectionText = dv;
13996         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13997         this.value = vv;
13998         
13999         
14000         
14001     },
14002     // private
14003     reset : function(){
14004         // overridden so that last data is reset..
14005         
14006         if(this.multiple){
14007             this.clearItem();
14008             return;
14009         }
14010         
14011         this.setValue(this.originalValue);
14012         //this.clearInvalid();
14013         this.lastData = false;
14014         if (this.view) {
14015             this.view.clearSelections();
14016         }
14017         
14018         this.validate();
14019     },
14020     // private
14021     findRecord : function(prop, value){
14022         var record;
14023         if(this.store.getCount() > 0){
14024             this.store.each(function(r){
14025                 if(r.data[prop] == value){
14026                     record = r;
14027                     return false;
14028                 }
14029                 return true;
14030             });
14031         }
14032         return record;
14033     },
14034     
14035     getName: function()
14036     {
14037         // returns hidden if it's set..
14038         if (!this.rendered) {return ''};
14039         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
14040         
14041     },
14042     // private
14043     onViewMove : function(e, t){
14044         this.inKeyMode = false;
14045     },
14046
14047     // private
14048     onViewOver : function(e, t){
14049         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14050             return;
14051         }
14052         var item = this.view.findItemFromChild(t);
14053         
14054         if(item){
14055             var index = this.view.indexOf(item);
14056             this.select(index, false);
14057         }
14058     },
14059
14060     // private
14061     onViewClick : function(view, doFocus, el, e)
14062     {
14063         var index = this.view.getSelectedIndexes()[0];
14064         
14065         var r = this.store.getAt(index);
14066         
14067         if(this.tickable){
14068             
14069             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14070                 return;
14071             }
14072             
14073             var rm = false;
14074             var _this = this;
14075             
14076             Roo.each(this.tickItems, function(v,k){
14077                 
14078                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14079                     Roo.log(v);
14080                     _this.tickItems.splice(k, 1);
14081                     
14082                     if(typeof(e) == 'undefined' && view == false){
14083                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14084                     }
14085                     
14086                     rm = true;
14087                     return;
14088                 }
14089             });
14090             
14091             if(rm){
14092                 return;
14093             }
14094             
14095             if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14096                 this.tickItems.push(r.data);
14097             }
14098             
14099             if(typeof(e) == 'undefined' && view == false){
14100                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14101             }
14102                     
14103             return;
14104         }
14105         
14106         if(r){
14107             this.onSelect(r, index);
14108         }
14109         if(doFocus !== false && !this.blockFocus){
14110             this.inputEl().focus();
14111         }
14112     },
14113
14114     // private
14115     restrictHeight : function(){
14116         //this.innerList.dom.style.height = '';
14117         //var inner = this.innerList.dom;
14118         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14119         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14120         //this.list.beginUpdate();
14121         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14122         this.list.alignTo(this.inputEl(), this.listAlign);
14123         this.list.alignTo(this.inputEl(), this.listAlign);
14124         //this.list.endUpdate();
14125     },
14126
14127     // private
14128     onEmptyResults : function(){
14129         
14130         if(this.tickable && this.editable){
14131             this.hasFocus = false;
14132             this.restrictHeight();
14133             return;
14134         }
14135         
14136         this.collapse();
14137     },
14138
14139     /**
14140      * Returns true if the dropdown list is expanded, else false.
14141      */
14142     isExpanded : function(){
14143         return this.list.isVisible();
14144     },
14145
14146     /**
14147      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14148      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14149      * @param {String} value The data value of the item to select
14150      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14151      * selected item if it is not currently in view (defaults to true)
14152      * @return {Boolean} True if the value matched an item in the list, else false
14153      */
14154     selectByValue : function(v, scrollIntoView){
14155         if(v !== undefined && v !== null){
14156             var r = this.findRecord(this.valueField || this.displayField, v);
14157             if(r){
14158                 this.select(this.store.indexOf(r), scrollIntoView);
14159                 return true;
14160             }
14161         }
14162         return false;
14163     },
14164
14165     /**
14166      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14167      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14168      * @param {Number} index The zero-based index of the list item to select
14169      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14170      * selected item if it is not currently in view (defaults to true)
14171      */
14172     select : function(index, scrollIntoView){
14173         this.selectedIndex = index;
14174         this.view.select(index);
14175         if(scrollIntoView !== false){
14176             var el = this.view.getNode(index);
14177             /*
14178              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14179              */
14180             if(el){
14181                 this.list.scrollChildIntoView(el, false);
14182             }
14183         }
14184     },
14185
14186     // private
14187     selectNext : function(){
14188         var ct = this.store.getCount();
14189         if(ct > 0){
14190             if(this.selectedIndex == -1){
14191                 this.select(0);
14192             }else if(this.selectedIndex < ct-1){
14193                 this.select(this.selectedIndex+1);
14194             }
14195         }
14196     },
14197
14198     // private
14199     selectPrev : function(){
14200         var ct = this.store.getCount();
14201         if(ct > 0){
14202             if(this.selectedIndex == -1){
14203                 this.select(0);
14204             }else if(this.selectedIndex != 0){
14205                 this.select(this.selectedIndex-1);
14206             }
14207         }
14208     },
14209
14210     // private
14211     onKeyUp : function(e){
14212         if(this.editable !== false && !e.isSpecialKey()){
14213             this.lastKey = e.getKey();
14214             this.dqTask.delay(this.queryDelay);
14215         }
14216     },
14217
14218     // private
14219     validateBlur : function(){
14220         return !this.list || !this.list.isVisible();   
14221     },
14222
14223     // private
14224     initQuery : function(){
14225         
14226         var v = this.getRawValue();
14227         
14228         if(this.tickable && this.editable){
14229             v = this.tickableInputEl().getValue();
14230         }
14231         
14232         this.doQuery(v);
14233     },
14234
14235     // private
14236     doForce : function(){
14237         if(this.inputEl().dom.value.length > 0){
14238             this.inputEl().dom.value =
14239                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14240              
14241         }
14242     },
14243
14244     /**
14245      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
14246      * query allowing the query action to be canceled if needed.
14247      * @param {String} query The SQL query to execute
14248      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14249      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
14250      * saved in the current store (defaults to false)
14251      */
14252     doQuery : function(q, forceAll){
14253         
14254         if(q === undefined || q === null){
14255             q = '';
14256         }
14257         var qe = {
14258             query: q,
14259             forceAll: forceAll,
14260             combo: this,
14261             cancel:false
14262         };
14263         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14264             return false;
14265         }
14266         q = qe.query;
14267         
14268         forceAll = qe.forceAll;
14269         if(forceAll === true || (q.length >= this.minChars)){
14270             
14271             this.hasQuery = true;
14272             
14273             if(this.lastQuery != q || this.alwaysQuery){
14274                 this.lastQuery = q;
14275                 if(this.mode == 'local'){
14276                     this.selectedIndex = -1;
14277                     if(forceAll){
14278                         this.store.clearFilter();
14279                     }else{
14280                         
14281                         if(this.specialFilter){
14282                             this.fireEvent('specialfilter', this);
14283                             this.onLoad();
14284                             return;
14285                         }
14286                         
14287                         this.store.filter(this.displayField, q);
14288                     }
14289                     
14290                     this.store.fireEvent("datachanged", this.store);
14291                     
14292                     this.onLoad();
14293                     
14294                     
14295                 }else{
14296                     
14297                     this.store.baseParams[this.queryParam] = q;
14298                     
14299                     var options = {params : this.getParams(q)};
14300                     
14301                     if(this.loadNext){
14302                         options.add = true;
14303                         options.params.start = this.page * this.pageSize;
14304                     }
14305                     
14306                     this.store.load(options);
14307                     
14308                     /*
14309                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
14310                      *  we should expand the list on onLoad
14311                      *  so command out it
14312                      */
14313 //                    this.expand();
14314                 }
14315             }else{
14316                 this.selectedIndex = -1;
14317                 this.onLoad();   
14318             }
14319         }
14320         
14321         this.loadNext = false;
14322     },
14323     
14324     // private
14325     getParams : function(q){
14326         var p = {};
14327         //p[this.queryParam] = q;
14328         
14329         if(this.pageSize){
14330             p.start = 0;
14331             p.limit = this.pageSize;
14332         }
14333         return p;
14334     },
14335
14336     /**
14337      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14338      */
14339     collapse : function(){
14340         if(!this.isExpanded()){
14341             return;
14342         }
14343         
14344         this.list.hide();
14345         
14346         this.hasFocus = false;
14347         
14348         if(this.tickable){
14349             this.okBtn.hide();
14350             this.cancelBtn.hide();
14351             this.trigger.show();
14352             
14353             if(this.editable){
14354                 this.tickableInputEl().dom.value = '';
14355                 this.tickableInputEl().blur();
14356             }
14357             
14358         }
14359         
14360         Roo.get(document).un('mousedown', this.collapseIf, this);
14361         Roo.get(document).un('mousewheel', this.collapseIf, this);
14362         if (!this.editable) {
14363             Roo.get(document).un('keydown', this.listKeyPress, this);
14364         }
14365         this.fireEvent('collapse', this);
14366         
14367         this.validate();
14368     },
14369
14370     // private
14371     collapseIf : function(e){
14372         var in_combo  = e.within(this.el);
14373         var in_list =  e.within(this.list);
14374         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14375         
14376         if (in_combo || in_list || is_list) {
14377             //e.stopPropagation();
14378             return;
14379         }
14380         
14381         if(this.tickable){
14382             this.onTickableFooterButtonClick(e, false, false);
14383         }
14384
14385         this.collapse();
14386         
14387     },
14388
14389     /**
14390      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14391      */
14392     expand : function(){
14393        
14394         if(this.isExpanded() || !this.hasFocus){
14395             return;
14396         }
14397         
14398         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14399         this.list.setWidth(lw);
14400         
14401         Roo.log('expand');
14402         
14403         this.list.show();
14404         
14405         this.restrictHeight();
14406         
14407         if(this.tickable){
14408             
14409             this.tickItems = Roo.apply([], this.item);
14410             
14411             this.okBtn.show();
14412             this.cancelBtn.show();
14413             this.trigger.hide();
14414             
14415             if(this.editable){
14416                 this.tickableInputEl().focus();
14417             }
14418             
14419         }
14420         
14421         Roo.get(document).on('mousedown', this.collapseIf, this);
14422         Roo.get(document).on('mousewheel', this.collapseIf, this);
14423         if (!this.editable) {
14424             Roo.get(document).on('keydown', this.listKeyPress, this);
14425         }
14426         
14427         this.fireEvent('expand', this);
14428     },
14429
14430     // private
14431     // Implements the default empty TriggerField.onTriggerClick function
14432     onTriggerClick : function(e)
14433     {
14434         Roo.log('trigger click');
14435         
14436         if(this.disabled || !this.triggerList){
14437             return;
14438         }
14439         
14440         this.page = 0;
14441         this.loadNext = false;
14442         
14443         if(this.isExpanded()){
14444             this.collapse();
14445             if (!this.blockFocus) {
14446                 this.inputEl().focus();
14447             }
14448             
14449         }else {
14450             this.hasFocus = true;
14451             if(this.triggerAction == 'all') {
14452                 this.doQuery(this.allQuery, true);
14453             } else {
14454                 this.doQuery(this.getRawValue());
14455             }
14456             if (!this.blockFocus) {
14457                 this.inputEl().focus();
14458             }
14459         }
14460     },
14461     
14462     onTickableTriggerClick : function(e)
14463     {
14464         if(this.disabled){
14465             return;
14466         }
14467         
14468         this.page = 0;
14469         this.loadNext = false;
14470         this.hasFocus = true;
14471         
14472         if(this.triggerAction == 'all') {
14473             this.doQuery(this.allQuery, true);
14474         } else {
14475             this.doQuery(this.getRawValue());
14476         }
14477     },
14478     
14479     onSearchFieldClick : function(e)
14480     {
14481         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14482             this.onTickableFooterButtonClick(e, false, false);
14483             return;
14484         }
14485         
14486         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14487             return;
14488         }
14489         
14490         this.page = 0;
14491         this.loadNext = false;
14492         this.hasFocus = true;
14493         
14494         if(this.triggerAction == 'all') {
14495             this.doQuery(this.allQuery, true);
14496         } else {
14497             this.doQuery(this.getRawValue());
14498         }
14499     },
14500     
14501     listKeyPress : function(e)
14502     {
14503         //Roo.log('listkeypress');
14504         // scroll to first matching element based on key pres..
14505         if (e.isSpecialKey()) {
14506             return false;
14507         }
14508         var k = String.fromCharCode(e.getKey()).toUpperCase();
14509         //Roo.log(k);
14510         var match  = false;
14511         var csel = this.view.getSelectedNodes();
14512         var cselitem = false;
14513         if (csel.length) {
14514             var ix = this.view.indexOf(csel[0]);
14515             cselitem  = this.store.getAt(ix);
14516             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14517                 cselitem = false;
14518             }
14519             
14520         }
14521         
14522         this.store.each(function(v) { 
14523             if (cselitem) {
14524                 // start at existing selection.
14525                 if (cselitem.id == v.id) {
14526                     cselitem = false;
14527                 }
14528                 return true;
14529             }
14530                 
14531             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14532                 match = this.store.indexOf(v);
14533                 return false;
14534             }
14535             return true;
14536         }, this);
14537         
14538         if (match === false) {
14539             return true; // no more action?
14540         }
14541         // scroll to?
14542         this.view.select(match);
14543         var sn = Roo.get(this.view.getSelectedNodes()[0]);
14544         sn.scrollIntoView(sn.dom.parentNode, false);
14545     },
14546     
14547     onViewScroll : function(e, t){
14548         
14549         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){
14550             return;
14551         }
14552         
14553         this.hasQuery = true;
14554         
14555         this.loading = this.list.select('.loading', true).first();
14556         
14557         if(this.loading === null){
14558             this.list.createChild({
14559                 tag: 'div',
14560                 cls: 'loading roo-select2-more-results roo-select2-active',
14561                 html: 'Loading more results...'
14562             });
14563             
14564             this.loading = this.list.select('.loading', true).first();
14565             
14566             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14567             
14568             this.loading.hide();
14569         }
14570         
14571         this.loading.show();
14572         
14573         var _combo = this;
14574         
14575         this.page++;
14576         this.loadNext = true;
14577         
14578         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14579         
14580         return;
14581     },
14582     
14583     addItem : function(o)
14584     {   
14585         var dv = ''; // display value
14586         
14587         if (this.displayField) {
14588             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14589         } else {
14590             // this is an error condition!!!
14591             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14592         }
14593         
14594         if(!dv.length){
14595             return;
14596         }
14597         
14598         var choice = this.choices.createChild({
14599             tag: 'li',
14600             cls: 'roo-select2-search-choice',
14601             cn: [
14602                 {
14603                     tag: 'div',
14604                     html: dv
14605                 },
14606                 {
14607                     tag: 'a',
14608                     href: '#',
14609                     cls: 'roo-select2-search-choice-close fa fa-times',
14610                     tabindex: '-1'
14611                 }
14612             ]
14613             
14614         }, this.searchField);
14615         
14616         var close = choice.select('a.roo-select2-search-choice-close', true).first();
14617         
14618         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14619         
14620         this.item.push(o);
14621         
14622         this.lastData = o;
14623         
14624         this.syncValue();
14625         
14626         this.inputEl().dom.value = '';
14627         
14628         this.validate();
14629     },
14630     
14631     onRemoveItem : function(e, _self, o)
14632     {
14633         e.preventDefault();
14634         
14635         this.lastItem = Roo.apply([], this.item);
14636         
14637         var index = this.item.indexOf(o.data) * 1;
14638         
14639         if( index < 0){
14640             Roo.log('not this item?!');
14641             return;
14642         }
14643         
14644         this.item.splice(index, 1);
14645         o.item.remove();
14646         
14647         this.syncValue();
14648         
14649         this.fireEvent('remove', this, e);
14650         
14651         this.validate();
14652         
14653     },
14654     
14655     syncValue : function()
14656     {
14657         if(!this.item.length){
14658             this.clearValue();
14659             return;
14660         }
14661             
14662         var value = [];
14663         var _this = this;
14664         Roo.each(this.item, function(i){
14665             if(_this.valueField){
14666                 value.push(i[_this.valueField]);
14667                 return;
14668             }
14669
14670             value.push(i);
14671         });
14672
14673         this.value = value.join(',');
14674
14675         if(this.hiddenField){
14676             this.hiddenField.dom.value = this.value;
14677         }
14678         
14679         this.store.fireEvent("datachanged", this.store);
14680         
14681         this.validate();
14682     },
14683     
14684     clearItem : function()
14685     {
14686         if(!this.multiple){
14687             return;
14688         }
14689         
14690         this.item = [];
14691         
14692         Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14693            c.remove();
14694         });
14695         
14696         this.syncValue();
14697         
14698         this.validate();
14699         
14700         if(this.tickable && !Roo.isTouch){
14701             this.view.refresh();
14702         }
14703     },
14704     
14705     inputEl: function ()
14706     {
14707         if(Roo.isIOS && this.useNativeIOS){
14708             return this.el.select('select.roo-ios-select', true).first();
14709         }
14710         
14711         if(Roo.isTouch && this.mobileTouchView){
14712             return this.el.select('input.form-control',true).first();
14713         }
14714         
14715         if(this.tickable){
14716             return this.searchField;
14717         }
14718         
14719         return this.el.select('input.form-control',true).first();
14720     },
14721     
14722     onTickableFooterButtonClick : function(e, btn, el)
14723     {
14724         e.preventDefault();
14725         
14726         this.lastItem = Roo.apply([], this.item);
14727         
14728         if(btn && btn.name == 'cancel'){
14729             this.tickItems = Roo.apply([], this.item);
14730             this.collapse();
14731             return;
14732         }
14733         
14734         this.clearItem();
14735         
14736         var _this = this;
14737         
14738         Roo.each(this.tickItems, function(o){
14739             _this.addItem(o);
14740         });
14741         
14742         this.collapse();
14743         
14744     },
14745     
14746     validate : function()
14747     {
14748         if(this.getVisibilityEl().hasClass('hidden')){
14749             return true;
14750         }
14751         
14752         var v = this.getRawValue();
14753         
14754         if(this.multiple){
14755             v = this.getValue();
14756         }
14757         
14758         if(this.disabled || this.allowBlank || v.length){
14759             this.markValid();
14760             return true;
14761         }
14762         
14763         this.markInvalid();
14764         return false;
14765     },
14766     
14767     tickableInputEl : function()
14768     {
14769         if(!this.tickable || !this.editable){
14770             return this.inputEl();
14771         }
14772         
14773         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14774     },
14775     
14776     
14777     getAutoCreateTouchView : function()
14778     {
14779         var id = Roo.id();
14780         
14781         var cfg = {
14782             cls: 'form-group' //input-group
14783         };
14784         
14785         var input =  {
14786             tag: 'input',
14787             id : id,
14788             type : this.inputType,
14789             cls : 'form-control x-combo-noedit',
14790             autocomplete: 'new-password',
14791             placeholder : this.placeholder || '',
14792             readonly : true
14793         };
14794         
14795         if (this.name) {
14796             input.name = this.name;
14797         }
14798         
14799         if (this.size) {
14800             input.cls += ' input-' + this.size;
14801         }
14802         
14803         if (this.disabled) {
14804             input.disabled = true;
14805         }
14806         
14807         var inputblock = {
14808             cls : '',
14809             cn : [
14810                 input
14811             ]
14812         };
14813         
14814         if(this.before){
14815             inputblock.cls += ' input-group';
14816             
14817             inputblock.cn.unshift({
14818                 tag :'span',
14819                 cls : 'input-group-addon',
14820                 html : this.before
14821             });
14822         }
14823         
14824         if(this.removable && !this.multiple){
14825             inputblock.cls += ' roo-removable';
14826             
14827             inputblock.cn.push({
14828                 tag: 'button',
14829                 html : 'x',
14830                 cls : 'roo-combo-removable-btn close'
14831             });
14832         }
14833
14834         if(this.hasFeedback && !this.allowBlank){
14835             
14836             inputblock.cls += ' has-feedback';
14837             
14838             inputblock.cn.push({
14839                 tag: 'span',
14840                 cls: 'glyphicon form-control-feedback'
14841             });
14842             
14843         }
14844         
14845         if (this.after) {
14846             
14847             inputblock.cls += (this.before) ? '' : ' input-group';
14848             
14849             inputblock.cn.push({
14850                 tag :'span',
14851                 cls : 'input-group-addon',
14852                 html : this.after
14853             });
14854         }
14855
14856         var box = {
14857             tag: 'div',
14858             cn: [
14859                 {
14860                     tag: 'input',
14861                     type : 'hidden',
14862                     cls: 'form-hidden-field'
14863                 },
14864                 inputblock
14865             ]
14866             
14867         };
14868         
14869         if(this.multiple){
14870             box = {
14871                 tag: 'div',
14872                 cn: [
14873                     {
14874                         tag: 'input',
14875                         type : 'hidden',
14876                         cls: 'form-hidden-field'
14877                     },
14878                     {
14879                         tag: 'ul',
14880                         cls: 'roo-select2-choices',
14881                         cn:[
14882                             {
14883                                 tag: 'li',
14884                                 cls: 'roo-select2-search-field',
14885                                 cn: [
14886
14887                                     inputblock
14888                                 ]
14889                             }
14890                         ]
14891                     }
14892                 ]
14893             }
14894         };
14895         
14896         var combobox = {
14897             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14898             cn: [
14899                 box
14900             ]
14901         };
14902         
14903         if(!this.multiple && this.showToggleBtn){
14904             
14905             var caret = {
14906                         tag: 'span',
14907                         cls: 'caret'
14908             };
14909             
14910             if (this.caret != false) {
14911                 caret = {
14912                      tag: 'i',
14913                      cls: 'fa fa-' + this.caret
14914                 };
14915                 
14916             }
14917             
14918             combobox.cn.push({
14919                 tag :'span',
14920                 cls : 'input-group-addon btn dropdown-toggle',
14921                 cn : [
14922                     caret,
14923                     {
14924                         tag: 'span',
14925                         cls: 'combobox-clear',
14926                         cn  : [
14927                             {
14928                                 tag : 'i',
14929                                 cls: 'icon-remove'
14930                             }
14931                         ]
14932                     }
14933                 ]
14934
14935             })
14936         }
14937         
14938         if(this.multiple){
14939             combobox.cls += ' roo-select2-container-multi';
14940         }
14941         
14942         var align = this.labelAlign || this.parentLabelAlign();
14943         
14944         if (align ==='left' && this.fieldLabel.length) {
14945
14946             cfg.cn = [
14947                 {
14948                    tag : 'i',
14949                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14950                    tooltip : 'This field is required'
14951                 },
14952                 {
14953                     tag: 'label',
14954                     cls : 'control-label',
14955                     html : this.fieldLabel
14956
14957                 },
14958                 {
14959                     cls : '', 
14960                     cn: [
14961                         combobox
14962                     ]
14963                 }
14964             ];
14965             
14966             var labelCfg = cfg.cn[1];
14967             var contentCfg = cfg.cn[2];
14968             
14969
14970             if(this.indicatorpos == 'right'){
14971                 cfg.cn = [
14972                     {
14973                         tag: 'label',
14974                         'for' :  id,
14975                         cls : 'control-label',
14976                         cn : [
14977                             {
14978                                 tag : 'span',
14979                                 html : this.fieldLabel
14980                             },
14981                             {
14982                                 tag : 'i',
14983                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14984                                 tooltip : 'This field is required'
14985                             }
14986                         ]
14987                     },
14988                     {
14989                         cls : "",
14990                         cn: [
14991                             combobox
14992                         ]
14993                     }
14994
14995                 ];
14996                 
14997                 labelCfg = cfg.cn[0];
14998                 contentCfg = cfg.cn[1];
14999             }
15000             
15001            
15002             
15003             if(this.labelWidth > 12){
15004                 labelCfg.style = "width: " + this.labelWidth + 'px';
15005             }
15006             
15007             if(this.labelWidth < 13 && this.labelmd == 0){
15008                 this.labelmd = this.labelWidth;
15009             }
15010             
15011             if(this.labellg > 0){
15012                 labelCfg.cls += ' col-lg-' + this.labellg;
15013                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15014             }
15015             
15016             if(this.labelmd > 0){
15017                 labelCfg.cls += ' col-md-' + this.labelmd;
15018                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15019             }
15020             
15021             if(this.labelsm > 0){
15022                 labelCfg.cls += ' col-sm-' + this.labelsm;
15023                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15024             }
15025             
15026             if(this.labelxs > 0){
15027                 labelCfg.cls += ' col-xs-' + this.labelxs;
15028                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15029             }
15030                 
15031                 
15032         } else if ( this.fieldLabel.length) {
15033             cfg.cn = [
15034                 {
15035                    tag : 'i',
15036                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15037                    tooltip : 'This field is required'
15038                 },
15039                 {
15040                     tag: 'label',
15041                     cls : 'control-label',
15042                     html : this.fieldLabel
15043
15044                 },
15045                 {
15046                     cls : '', 
15047                     cn: [
15048                         combobox
15049                     ]
15050                 }
15051             ];
15052             
15053             if(this.indicatorpos == 'right'){
15054                 cfg.cn = [
15055                     {
15056                         tag: 'label',
15057                         cls : 'control-label',
15058                         html : this.fieldLabel,
15059                         cn : [
15060                             {
15061                                tag : 'i',
15062                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15063                                tooltip : 'This field is required'
15064                             }
15065                         ]
15066                     },
15067                     {
15068                         cls : '', 
15069                         cn: [
15070                             combobox
15071                         ]
15072                     }
15073                 ];
15074             }
15075         } else {
15076             cfg.cn = combobox;    
15077         }
15078         
15079         
15080         var settings = this;
15081         
15082         ['xs','sm','md','lg'].map(function(size){
15083             if (settings[size]) {
15084                 cfg.cls += ' col-' + size + '-' + settings[size];
15085             }
15086         });
15087         
15088         return cfg;
15089     },
15090     
15091     initTouchView : function()
15092     {
15093         this.renderTouchView();
15094         
15095         this.touchViewEl.on('scroll', function(){
15096             this.el.dom.scrollTop = 0;
15097         }, this);
15098         
15099         this.originalValue = this.getValue();
15100         
15101         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15102         
15103         this.inputEl().on("click", this.showTouchView, this);
15104         if (this.triggerEl) {
15105             this.triggerEl.on("click", this.showTouchView, this);
15106         }
15107         
15108         
15109         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15110         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15111         
15112         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15113         
15114         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15115         this.store.on('load', this.onTouchViewLoad, this);
15116         this.store.on('loadexception', this.onTouchViewLoadException, this);
15117         
15118         if(this.hiddenName){
15119             
15120             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15121             
15122             this.hiddenField.dom.value =
15123                 this.hiddenValue !== undefined ? this.hiddenValue :
15124                 this.value !== undefined ? this.value : '';
15125         
15126             this.el.dom.removeAttribute('name');
15127             this.hiddenField.dom.setAttribute('name', this.hiddenName);
15128         }
15129         
15130         if(this.multiple){
15131             this.choices = this.el.select('ul.roo-select2-choices', true).first();
15132             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15133         }
15134         
15135         if(this.removable && !this.multiple){
15136             var close = this.closeTriggerEl();
15137             if(close){
15138                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15139                 close.on('click', this.removeBtnClick, this, close);
15140             }
15141         }
15142         /*
15143          * fix the bug in Safari iOS8
15144          */
15145         this.inputEl().on("focus", function(e){
15146             document.activeElement.blur();
15147         }, this);
15148         
15149         return;
15150         
15151         
15152     },
15153     
15154     renderTouchView : function()
15155     {
15156         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15157         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15158         
15159         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15160         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15161         
15162         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15163         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15164         this.touchViewBodyEl.setStyle('overflow', 'auto');
15165         
15166         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15167         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15168         
15169         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15170         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15171         
15172     },
15173     
15174     showTouchView : function()
15175     {
15176         if(this.disabled){
15177             return;
15178         }
15179         
15180         this.touchViewHeaderEl.hide();
15181
15182         if(this.modalTitle.length){
15183             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15184             this.touchViewHeaderEl.show();
15185         }
15186
15187         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15188         this.touchViewEl.show();
15189
15190         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15191         
15192         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15193         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15194
15195         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15196
15197         if(this.modalTitle.length){
15198             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15199         }
15200         
15201         this.touchViewBodyEl.setHeight(bodyHeight);
15202
15203         if(this.animate){
15204             var _this = this;
15205             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15206         }else{
15207             this.touchViewEl.addClass('in');
15208         }
15209
15210         this.doTouchViewQuery();
15211         
15212     },
15213     
15214     hideTouchView : function()
15215     {
15216         this.touchViewEl.removeClass('in');
15217
15218         if(this.animate){
15219             var _this = this;
15220             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15221         }else{
15222             this.touchViewEl.setStyle('display', 'none');
15223         }
15224         
15225     },
15226     
15227     setTouchViewValue : function()
15228     {
15229         if(this.multiple){
15230             this.clearItem();
15231         
15232             var _this = this;
15233
15234             Roo.each(this.tickItems, function(o){
15235                 this.addItem(o);
15236             }, this);
15237         }
15238         
15239         this.hideTouchView();
15240     },
15241     
15242     doTouchViewQuery : function()
15243     {
15244         var qe = {
15245             query: '',
15246             forceAll: true,
15247             combo: this,
15248             cancel:false
15249         };
15250         
15251         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15252             return false;
15253         }
15254         
15255         if(!this.alwaysQuery || this.mode == 'local'){
15256             this.onTouchViewLoad();
15257             return;
15258         }
15259         
15260         this.store.load();
15261     },
15262     
15263     onTouchViewBeforeLoad : function(combo,opts)
15264     {
15265         return;
15266     },
15267
15268     // private
15269     onTouchViewLoad : function()
15270     {
15271         if(this.store.getCount() < 1){
15272             this.onTouchViewEmptyResults();
15273             return;
15274         }
15275         
15276         this.clearTouchView();
15277         
15278         var rawValue = this.getRawValue();
15279         
15280         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15281         
15282         this.tickItems = [];
15283         
15284         this.store.data.each(function(d, rowIndex){
15285             var row = this.touchViewListGroup.createChild(template);
15286             
15287             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15288                 row.addClass(d.data.cls);
15289             }
15290             
15291             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15292                 var cfg = {
15293                     data : d.data,
15294                     html : d.data[this.displayField]
15295                 };
15296                 
15297                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15298                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15299                 }
15300             }
15301             row.removeClass('selected');
15302             if(!this.multiple && this.valueField &&
15303                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15304             {
15305                 // radio buttons..
15306                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15307                 row.addClass('selected');
15308             }
15309             
15310             if(this.multiple && this.valueField &&
15311                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15312             {
15313                 
15314                 // checkboxes...
15315                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15316                 this.tickItems.push(d.data);
15317             }
15318             
15319             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15320             
15321         }, this);
15322         
15323         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15324         
15325         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15326
15327         if(this.modalTitle.length){
15328             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15329         }
15330
15331         var listHeight = this.touchViewListGroup.getHeight();
15332         
15333         var _this = this;
15334         
15335         if(firstChecked && listHeight > bodyHeight){
15336             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15337         }
15338         
15339     },
15340     
15341     onTouchViewLoadException : function()
15342     {
15343         this.hideTouchView();
15344     },
15345     
15346     onTouchViewEmptyResults : function()
15347     {
15348         this.clearTouchView();
15349         
15350         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15351         
15352         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15353         
15354     },
15355     
15356     clearTouchView : function()
15357     {
15358         this.touchViewListGroup.dom.innerHTML = '';
15359     },
15360     
15361     onTouchViewClick : function(e, el, o)
15362     {
15363         e.preventDefault();
15364         
15365         var row = o.row;
15366         var rowIndex = o.rowIndex;
15367         
15368         var r = this.store.getAt(rowIndex);
15369         
15370         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15371             
15372             if(!this.multiple){
15373                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15374                     c.dom.removeAttribute('checked');
15375                 }, this);
15376
15377                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15378
15379                 this.setFromData(r.data);
15380
15381                 var close = this.closeTriggerEl();
15382
15383                 if(close){
15384                     close.show();
15385                 }
15386
15387                 this.hideTouchView();
15388
15389                 this.fireEvent('select', this, r, rowIndex);
15390
15391                 return;
15392             }
15393
15394             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15395                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15396                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15397                 return;
15398             }
15399
15400             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15401             this.addItem(r.data);
15402             this.tickItems.push(r.data);
15403         }
15404     },
15405     
15406     getAutoCreateNativeIOS : function()
15407     {
15408         var cfg = {
15409             cls: 'form-group' //input-group,
15410         };
15411         
15412         var combobox =  {
15413             tag: 'select',
15414             cls : 'roo-ios-select'
15415         };
15416         
15417         if (this.name) {
15418             combobox.name = this.name;
15419         }
15420         
15421         if (this.disabled) {
15422             combobox.disabled = true;
15423         }
15424         
15425         var settings = this;
15426         
15427         ['xs','sm','md','lg'].map(function(size){
15428             if (settings[size]) {
15429                 cfg.cls += ' col-' + size + '-' + settings[size];
15430             }
15431         });
15432         
15433         cfg.cn = combobox;
15434         
15435         return cfg;
15436         
15437     },
15438     
15439     initIOSView : function()
15440     {
15441         this.store.on('load', this.onIOSViewLoad, this);
15442         
15443         return;
15444     },
15445     
15446     onIOSViewLoad : function()
15447     {
15448         if(this.store.getCount() < 1){
15449             return;
15450         }
15451         
15452         this.clearIOSView();
15453         
15454         if(this.allowBlank) {
15455             
15456             var default_text = '-- SELECT --';
15457             
15458             if(this.placeholder.length){
15459                 default_text = this.placeholder;
15460             }
15461             
15462             if(this.emptyTitle.length){
15463                 default_text += ' - ' + this.emptyTitle + ' -';
15464             }
15465             
15466             var opt = this.inputEl().createChild({
15467                 tag: 'option',
15468                 value : 0,
15469                 html : default_text
15470             });
15471             
15472             var o = {};
15473             o[this.valueField] = 0;
15474             o[this.displayField] = default_text;
15475             
15476             this.ios_options.push({
15477                 data : o,
15478                 el : opt
15479             });
15480             
15481         }
15482         
15483         this.store.data.each(function(d, rowIndex){
15484             
15485             var html = '';
15486             
15487             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15488                 html = d.data[this.displayField];
15489             }
15490             
15491             var value = '';
15492             
15493             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15494                 value = d.data[this.valueField];
15495             }
15496             
15497             var option = {
15498                 tag: 'option',
15499                 value : value,
15500                 html : html
15501             };
15502             
15503             if(this.value == d.data[this.valueField]){
15504                 option['selected'] = true;
15505             }
15506             
15507             var opt = this.inputEl().createChild(option);
15508             
15509             this.ios_options.push({
15510                 data : d.data,
15511                 el : opt
15512             });
15513             
15514         }, this);
15515         
15516         this.inputEl().on('change', function(){
15517            this.fireEvent('select', this);
15518         }, this);
15519         
15520     },
15521     
15522     clearIOSView: function()
15523     {
15524         this.inputEl().dom.innerHTML = '';
15525         
15526         this.ios_options = [];
15527     },
15528     
15529     setIOSValue: function(v)
15530     {
15531         this.value = v;
15532         
15533         if(!this.ios_options){
15534             return;
15535         }
15536         
15537         Roo.each(this.ios_options, function(opts){
15538            
15539            opts.el.dom.removeAttribute('selected');
15540            
15541            if(opts.data[this.valueField] != v){
15542                return;
15543            }
15544            
15545            opts.el.dom.setAttribute('selected', true);
15546            
15547         }, this);
15548     }
15549
15550     /** 
15551     * @cfg {Boolean} grow 
15552     * @hide 
15553     */
15554     /** 
15555     * @cfg {Number} growMin 
15556     * @hide 
15557     */
15558     /** 
15559     * @cfg {Number} growMax 
15560     * @hide 
15561     */
15562     /**
15563      * @hide
15564      * @method autoSize
15565      */
15566 });
15567
15568 Roo.apply(Roo.bootstrap.ComboBox,  {
15569     
15570     header : {
15571         tag: 'div',
15572         cls: 'modal-header',
15573         cn: [
15574             {
15575                 tag: 'h4',
15576                 cls: 'modal-title'
15577             }
15578         ]
15579     },
15580     
15581     body : {
15582         tag: 'div',
15583         cls: 'modal-body',
15584         cn: [
15585             {
15586                 tag: 'ul',
15587                 cls: 'list-group'
15588             }
15589         ]
15590     },
15591     
15592     listItemRadio : {
15593         tag: 'li',
15594         cls: 'list-group-item',
15595         cn: [
15596             {
15597                 tag: 'span',
15598                 cls: 'roo-combobox-list-group-item-value'
15599             },
15600             {
15601                 tag: 'div',
15602                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15603                 cn: [
15604                     {
15605                         tag: 'input',
15606                         type: 'radio'
15607                     },
15608                     {
15609                         tag: 'label'
15610                     }
15611                 ]
15612             }
15613         ]
15614     },
15615     
15616     listItemCheckbox : {
15617         tag: 'li',
15618         cls: 'list-group-item',
15619         cn: [
15620             {
15621                 tag: 'span',
15622                 cls: 'roo-combobox-list-group-item-value'
15623             },
15624             {
15625                 tag: 'div',
15626                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15627                 cn: [
15628                     {
15629                         tag: 'input',
15630                         type: 'checkbox'
15631                     },
15632                     {
15633                         tag: 'label'
15634                     }
15635                 ]
15636             }
15637         ]
15638     },
15639     
15640     emptyResult : {
15641         tag: 'div',
15642         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15643     },
15644     
15645     footer : {
15646         tag: 'div',
15647         cls: 'modal-footer',
15648         cn: [
15649             {
15650                 tag: 'div',
15651                 cls: 'row',
15652                 cn: [
15653                     {
15654                         tag: 'div',
15655                         cls: 'col-xs-6 text-left',
15656                         cn: {
15657                             tag: 'button',
15658                             cls: 'btn btn-danger roo-touch-view-cancel',
15659                             html: 'Cancel'
15660                         }
15661                     },
15662                     {
15663                         tag: 'div',
15664                         cls: 'col-xs-6 text-right',
15665                         cn: {
15666                             tag: 'button',
15667                             cls: 'btn btn-success roo-touch-view-ok',
15668                             html: 'OK'
15669                         }
15670                     }
15671                 ]
15672             }
15673         ]
15674         
15675     }
15676 });
15677
15678 Roo.apply(Roo.bootstrap.ComboBox,  {
15679     
15680     touchViewTemplate : {
15681         tag: 'div',
15682         cls: 'modal fade roo-combobox-touch-view',
15683         cn: [
15684             {
15685                 tag: 'div',
15686                 cls: 'modal-dialog',
15687                 style : 'position:fixed', // we have to fix position....
15688                 cn: [
15689                     {
15690                         tag: 'div',
15691                         cls: 'modal-content',
15692                         cn: [
15693                             Roo.bootstrap.ComboBox.header,
15694                             Roo.bootstrap.ComboBox.body,
15695                             Roo.bootstrap.ComboBox.footer
15696                         ]
15697                     }
15698                 ]
15699             }
15700         ]
15701     }
15702 });/*
15703  * Based on:
15704  * Ext JS Library 1.1.1
15705  * Copyright(c) 2006-2007, Ext JS, LLC.
15706  *
15707  * Originally Released Under LGPL - original licence link has changed is not relivant.
15708  *
15709  * Fork - LGPL
15710  * <script type="text/javascript">
15711  */
15712
15713 /**
15714  * @class Roo.View
15715  * @extends Roo.util.Observable
15716  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15717  * This class also supports single and multi selection modes. <br>
15718  * Create a data model bound view:
15719  <pre><code>
15720  var store = new Roo.data.Store(...);
15721
15722  var view = new Roo.View({
15723     el : "my-element",
15724     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15725  
15726     singleSelect: true,
15727     selectedClass: "ydataview-selected",
15728     store: store
15729  });
15730
15731  // listen for node click?
15732  view.on("click", function(vw, index, node, e){
15733  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15734  });
15735
15736  // load XML data
15737  dataModel.load("foobar.xml");
15738  </code></pre>
15739  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15740  * <br><br>
15741  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15742  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15743  * 
15744  * Note: old style constructor is still suported (container, template, config)
15745  * 
15746  * @constructor
15747  * Create a new View
15748  * @param {Object} config The config object
15749  * 
15750  */
15751 Roo.View = function(config, depreciated_tpl, depreciated_config){
15752     
15753     this.parent = false;
15754     
15755     if (typeof(depreciated_tpl) == 'undefined') {
15756         // new way.. - universal constructor.
15757         Roo.apply(this, config);
15758         this.el  = Roo.get(this.el);
15759     } else {
15760         // old format..
15761         this.el  = Roo.get(config);
15762         this.tpl = depreciated_tpl;
15763         Roo.apply(this, depreciated_config);
15764     }
15765     this.wrapEl  = this.el.wrap().wrap();
15766     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15767     
15768     
15769     if(typeof(this.tpl) == "string"){
15770         this.tpl = new Roo.Template(this.tpl);
15771     } else {
15772         // support xtype ctors..
15773         this.tpl = new Roo.factory(this.tpl, Roo);
15774     }
15775     
15776     
15777     this.tpl.compile();
15778     
15779     /** @private */
15780     this.addEvents({
15781         /**
15782          * @event beforeclick
15783          * Fires before a click is processed. Returns false to cancel the default action.
15784          * @param {Roo.View} this
15785          * @param {Number} index The index of the target node
15786          * @param {HTMLElement} node The target node
15787          * @param {Roo.EventObject} e The raw event object
15788          */
15789             "beforeclick" : true,
15790         /**
15791          * @event click
15792          * Fires when a template node is clicked.
15793          * @param {Roo.View} this
15794          * @param {Number} index The index of the target node
15795          * @param {HTMLElement} node The target node
15796          * @param {Roo.EventObject} e The raw event object
15797          */
15798             "click" : true,
15799         /**
15800          * @event dblclick
15801          * Fires when a template node is double clicked.
15802          * @param {Roo.View} this
15803          * @param {Number} index The index of the target node
15804          * @param {HTMLElement} node The target node
15805          * @param {Roo.EventObject} e The raw event object
15806          */
15807             "dblclick" : true,
15808         /**
15809          * @event contextmenu
15810          * Fires when a template node is right clicked.
15811          * @param {Roo.View} this
15812          * @param {Number} index The index of the target node
15813          * @param {HTMLElement} node The target node
15814          * @param {Roo.EventObject} e The raw event object
15815          */
15816             "contextmenu" : true,
15817         /**
15818          * @event selectionchange
15819          * Fires when the selected nodes change.
15820          * @param {Roo.View} this
15821          * @param {Array} selections Array of the selected nodes
15822          */
15823             "selectionchange" : true,
15824     
15825         /**
15826          * @event beforeselect
15827          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15828          * @param {Roo.View} this
15829          * @param {HTMLElement} node The node to be selected
15830          * @param {Array} selections Array of currently selected nodes
15831          */
15832             "beforeselect" : true,
15833         /**
15834          * @event preparedata
15835          * Fires on every row to render, to allow you to change the data.
15836          * @param {Roo.View} this
15837          * @param {Object} data to be rendered (change this)
15838          */
15839           "preparedata" : true
15840           
15841           
15842         });
15843
15844
15845
15846     this.el.on({
15847         "click": this.onClick,
15848         "dblclick": this.onDblClick,
15849         "contextmenu": this.onContextMenu,
15850         scope:this
15851     });
15852
15853     this.selections = [];
15854     this.nodes = [];
15855     this.cmp = new Roo.CompositeElementLite([]);
15856     if(this.store){
15857         this.store = Roo.factory(this.store, Roo.data);
15858         this.setStore(this.store, true);
15859     }
15860     
15861     if ( this.footer && this.footer.xtype) {
15862            
15863          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15864         
15865         this.footer.dataSource = this.store;
15866         this.footer.container = fctr;
15867         this.footer = Roo.factory(this.footer, Roo);
15868         fctr.insertFirst(this.el);
15869         
15870         // this is a bit insane - as the paging toolbar seems to detach the el..
15871 //        dom.parentNode.parentNode.parentNode
15872          // they get detached?
15873     }
15874     
15875     
15876     Roo.View.superclass.constructor.call(this);
15877     
15878     
15879 };
15880
15881 Roo.extend(Roo.View, Roo.util.Observable, {
15882     
15883      /**
15884      * @cfg {Roo.data.Store} store Data store to load data from.
15885      */
15886     store : false,
15887     
15888     /**
15889      * @cfg {String|Roo.Element} el The container element.
15890      */
15891     el : '',
15892     
15893     /**
15894      * @cfg {String|Roo.Template} tpl The template used by this View 
15895      */
15896     tpl : false,
15897     /**
15898      * @cfg {String} dataName the named area of the template to use as the data area
15899      *                          Works with domtemplates roo-name="name"
15900      */
15901     dataName: false,
15902     /**
15903      * @cfg {String} selectedClass The css class to add to selected nodes
15904      */
15905     selectedClass : "x-view-selected",
15906      /**
15907      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15908      */
15909     emptyText : "",
15910     
15911     /**
15912      * @cfg {String} text to display on mask (default Loading)
15913      */
15914     mask : false,
15915     /**
15916      * @cfg {Boolean} multiSelect Allow multiple selection
15917      */
15918     multiSelect : false,
15919     /**
15920      * @cfg {Boolean} singleSelect Allow single selection
15921      */
15922     singleSelect:  false,
15923     
15924     /**
15925      * @cfg {Boolean} toggleSelect - selecting 
15926      */
15927     toggleSelect : false,
15928     
15929     /**
15930      * @cfg {Boolean} tickable - selecting 
15931      */
15932     tickable : false,
15933     
15934     /**
15935      * Returns the element this view is bound to.
15936      * @return {Roo.Element}
15937      */
15938     getEl : function(){
15939         return this.wrapEl;
15940     },
15941     
15942     
15943
15944     /**
15945      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15946      */
15947     refresh : function(){
15948         //Roo.log('refresh');
15949         var t = this.tpl;
15950         
15951         // if we are using something like 'domtemplate', then
15952         // the what gets used is:
15953         // t.applySubtemplate(NAME, data, wrapping data..)
15954         // the outer template then get' applied with
15955         //     the store 'extra data'
15956         // and the body get's added to the
15957         //      roo-name="data" node?
15958         //      <span class='roo-tpl-{name}'></span> ?????
15959         
15960         
15961         
15962         this.clearSelections();
15963         this.el.update("");
15964         var html = [];
15965         var records = this.store.getRange();
15966         if(records.length < 1) {
15967             
15968             // is this valid??  = should it render a template??
15969             
15970             this.el.update(this.emptyText);
15971             return;
15972         }
15973         var el = this.el;
15974         if (this.dataName) {
15975             this.el.update(t.apply(this.store.meta)); //????
15976             el = this.el.child('.roo-tpl-' + this.dataName);
15977         }
15978         
15979         for(var i = 0, len = records.length; i < len; i++){
15980             var data = this.prepareData(records[i].data, i, records[i]);
15981             this.fireEvent("preparedata", this, data, i, records[i]);
15982             
15983             var d = Roo.apply({}, data);
15984             
15985             if(this.tickable){
15986                 Roo.apply(d, {'roo-id' : Roo.id()});
15987                 
15988                 var _this = this;
15989             
15990                 Roo.each(this.parent.item, function(item){
15991                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15992                         return;
15993                     }
15994                     Roo.apply(d, {'roo-data-checked' : 'checked'});
15995                 });
15996             }
15997             
15998             html[html.length] = Roo.util.Format.trim(
15999                 this.dataName ?
16000                     t.applySubtemplate(this.dataName, d, this.store.meta) :
16001                     t.apply(d)
16002             );
16003         }
16004         
16005         
16006         
16007         el.update(html.join(""));
16008         this.nodes = el.dom.childNodes;
16009         this.updateIndexes(0);
16010     },
16011     
16012
16013     /**
16014      * Function to override to reformat the data that is sent to
16015      * the template for each node.
16016      * DEPRICATED - use the preparedata event handler.
16017      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16018      * a JSON object for an UpdateManager bound view).
16019      */
16020     prepareData : function(data, index, record)
16021     {
16022         this.fireEvent("preparedata", this, data, index, record);
16023         return data;
16024     },
16025
16026     onUpdate : function(ds, record){
16027         // Roo.log('on update');   
16028         this.clearSelections();
16029         var index = this.store.indexOf(record);
16030         var n = this.nodes[index];
16031         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16032         n.parentNode.removeChild(n);
16033         this.updateIndexes(index, index);
16034     },
16035
16036     
16037     
16038 // --------- FIXME     
16039     onAdd : function(ds, records, index)
16040     {
16041         //Roo.log(['on Add', ds, records, index] );        
16042         this.clearSelections();
16043         if(this.nodes.length == 0){
16044             this.refresh();
16045             return;
16046         }
16047         var n = this.nodes[index];
16048         for(var i = 0, len = records.length; i < len; i++){
16049             var d = this.prepareData(records[i].data, i, records[i]);
16050             if(n){
16051                 this.tpl.insertBefore(n, d);
16052             }else{
16053                 
16054                 this.tpl.append(this.el, d);
16055             }
16056         }
16057         this.updateIndexes(index);
16058     },
16059
16060     onRemove : function(ds, record, index){
16061        // Roo.log('onRemove');
16062         this.clearSelections();
16063         var el = this.dataName  ?
16064             this.el.child('.roo-tpl-' + this.dataName) :
16065             this.el; 
16066         
16067         el.dom.removeChild(this.nodes[index]);
16068         this.updateIndexes(index);
16069     },
16070
16071     /**
16072      * Refresh an individual node.
16073      * @param {Number} index
16074      */
16075     refreshNode : function(index){
16076         this.onUpdate(this.store, this.store.getAt(index));
16077     },
16078
16079     updateIndexes : function(startIndex, endIndex){
16080         var ns = this.nodes;
16081         startIndex = startIndex || 0;
16082         endIndex = endIndex || ns.length - 1;
16083         for(var i = startIndex; i <= endIndex; i++){
16084             ns[i].nodeIndex = i;
16085         }
16086     },
16087
16088     /**
16089      * Changes the data store this view uses and refresh the view.
16090      * @param {Store} store
16091      */
16092     setStore : function(store, initial){
16093         if(!initial && this.store){
16094             this.store.un("datachanged", this.refresh);
16095             this.store.un("add", this.onAdd);
16096             this.store.un("remove", this.onRemove);
16097             this.store.un("update", this.onUpdate);
16098             this.store.un("clear", this.refresh);
16099             this.store.un("beforeload", this.onBeforeLoad);
16100             this.store.un("load", this.onLoad);
16101             this.store.un("loadexception", this.onLoad);
16102         }
16103         if(store){
16104           
16105             store.on("datachanged", this.refresh, this);
16106             store.on("add", this.onAdd, this);
16107             store.on("remove", this.onRemove, this);
16108             store.on("update", this.onUpdate, this);
16109             store.on("clear", this.refresh, this);
16110             store.on("beforeload", this.onBeforeLoad, this);
16111             store.on("load", this.onLoad, this);
16112             store.on("loadexception", this.onLoad, this);
16113         }
16114         
16115         if(store){
16116             this.refresh();
16117         }
16118     },
16119     /**
16120      * onbeforeLoad - masks the loading area.
16121      *
16122      */
16123     onBeforeLoad : function(store,opts)
16124     {
16125          //Roo.log('onBeforeLoad');   
16126         if (!opts.add) {
16127             this.el.update("");
16128         }
16129         this.el.mask(this.mask ? this.mask : "Loading" ); 
16130     },
16131     onLoad : function ()
16132     {
16133         this.el.unmask();
16134     },
16135     
16136
16137     /**
16138      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16139      * @param {HTMLElement} node
16140      * @return {HTMLElement} The template node
16141      */
16142     findItemFromChild : function(node){
16143         var el = this.dataName  ?
16144             this.el.child('.roo-tpl-' + this.dataName,true) :
16145             this.el.dom; 
16146         
16147         if(!node || node.parentNode == el){
16148                     return node;
16149             }
16150             var p = node.parentNode;
16151             while(p && p != el){
16152             if(p.parentNode == el){
16153                 return p;
16154             }
16155             p = p.parentNode;
16156         }
16157             return null;
16158     },
16159
16160     /** @ignore */
16161     onClick : function(e){
16162         var item = this.findItemFromChild(e.getTarget());
16163         if(item){
16164             var index = this.indexOf(item);
16165             if(this.onItemClick(item, index, e) !== false){
16166                 this.fireEvent("click", this, index, item, e);
16167             }
16168         }else{
16169             this.clearSelections();
16170         }
16171     },
16172
16173     /** @ignore */
16174     onContextMenu : function(e){
16175         var item = this.findItemFromChild(e.getTarget());
16176         if(item){
16177             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16178         }
16179     },
16180
16181     /** @ignore */
16182     onDblClick : function(e){
16183         var item = this.findItemFromChild(e.getTarget());
16184         if(item){
16185             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16186         }
16187     },
16188
16189     onItemClick : function(item, index, e)
16190     {
16191         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16192             return false;
16193         }
16194         if (this.toggleSelect) {
16195             var m = this.isSelected(item) ? 'unselect' : 'select';
16196             //Roo.log(m);
16197             var _t = this;
16198             _t[m](item, true, false);
16199             return true;
16200         }
16201         if(this.multiSelect || this.singleSelect){
16202             if(this.multiSelect && e.shiftKey && this.lastSelection){
16203                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16204             }else{
16205                 this.select(item, this.multiSelect && e.ctrlKey);
16206                 this.lastSelection = item;
16207             }
16208             
16209             if(!this.tickable){
16210                 e.preventDefault();
16211             }
16212             
16213         }
16214         return true;
16215     },
16216
16217     /**
16218      * Get the number of selected nodes.
16219      * @return {Number}
16220      */
16221     getSelectionCount : function(){
16222         return this.selections.length;
16223     },
16224
16225     /**
16226      * Get the currently selected nodes.
16227      * @return {Array} An array of HTMLElements
16228      */
16229     getSelectedNodes : function(){
16230         return this.selections;
16231     },
16232
16233     /**
16234      * Get the indexes of the selected nodes.
16235      * @return {Array}
16236      */
16237     getSelectedIndexes : function(){
16238         var indexes = [], s = this.selections;
16239         for(var i = 0, len = s.length; i < len; i++){
16240             indexes.push(s[i].nodeIndex);
16241         }
16242         return indexes;
16243     },
16244
16245     /**
16246      * Clear all selections
16247      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16248      */
16249     clearSelections : function(suppressEvent){
16250         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16251             this.cmp.elements = this.selections;
16252             this.cmp.removeClass(this.selectedClass);
16253             this.selections = [];
16254             if(!suppressEvent){
16255                 this.fireEvent("selectionchange", this, this.selections);
16256             }
16257         }
16258     },
16259
16260     /**
16261      * Returns true if the passed node is selected
16262      * @param {HTMLElement/Number} node The node or node index
16263      * @return {Boolean}
16264      */
16265     isSelected : function(node){
16266         var s = this.selections;
16267         if(s.length < 1){
16268             return false;
16269         }
16270         node = this.getNode(node);
16271         return s.indexOf(node) !== -1;
16272     },
16273
16274     /**
16275      * Selects nodes.
16276      * @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
16277      * @param {Boolean} keepExisting (optional) true to keep existing selections
16278      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16279      */
16280     select : function(nodeInfo, keepExisting, suppressEvent){
16281         if(nodeInfo instanceof Array){
16282             if(!keepExisting){
16283                 this.clearSelections(true);
16284             }
16285             for(var i = 0, len = nodeInfo.length; i < len; i++){
16286                 this.select(nodeInfo[i], true, true);
16287             }
16288             return;
16289         } 
16290         var node = this.getNode(nodeInfo);
16291         if(!node || this.isSelected(node)){
16292             return; // already selected.
16293         }
16294         if(!keepExisting){
16295             this.clearSelections(true);
16296         }
16297         
16298         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16299             Roo.fly(node).addClass(this.selectedClass);
16300             this.selections.push(node);
16301             if(!suppressEvent){
16302                 this.fireEvent("selectionchange", this, this.selections);
16303             }
16304         }
16305         
16306         
16307     },
16308       /**
16309      * Unselects nodes.
16310      * @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
16311      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16312      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16313      */
16314     unselect : function(nodeInfo, keepExisting, suppressEvent)
16315     {
16316         if(nodeInfo instanceof Array){
16317             Roo.each(this.selections, function(s) {
16318                 this.unselect(s, nodeInfo);
16319             }, this);
16320             return;
16321         }
16322         var node = this.getNode(nodeInfo);
16323         if(!node || !this.isSelected(node)){
16324             //Roo.log("not selected");
16325             return; // not selected.
16326         }
16327         // fireevent???
16328         var ns = [];
16329         Roo.each(this.selections, function(s) {
16330             if (s == node ) {
16331                 Roo.fly(node).removeClass(this.selectedClass);
16332
16333                 return;
16334             }
16335             ns.push(s);
16336         },this);
16337         
16338         this.selections= ns;
16339         this.fireEvent("selectionchange", this, this.selections);
16340     },
16341
16342     /**
16343      * Gets a template node.
16344      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16345      * @return {HTMLElement} The node or null if it wasn't found
16346      */
16347     getNode : function(nodeInfo){
16348         if(typeof nodeInfo == "string"){
16349             return document.getElementById(nodeInfo);
16350         }else if(typeof nodeInfo == "number"){
16351             return this.nodes[nodeInfo];
16352         }
16353         return nodeInfo;
16354     },
16355
16356     /**
16357      * Gets a range template nodes.
16358      * @param {Number} startIndex
16359      * @param {Number} endIndex
16360      * @return {Array} An array of nodes
16361      */
16362     getNodes : function(start, end){
16363         var ns = this.nodes;
16364         start = start || 0;
16365         end = typeof end == "undefined" ? ns.length - 1 : end;
16366         var nodes = [];
16367         if(start <= end){
16368             for(var i = start; i <= end; i++){
16369                 nodes.push(ns[i]);
16370             }
16371         } else{
16372             for(var i = start; i >= end; i--){
16373                 nodes.push(ns[i]);
16374             }
16375         }
16376         return nodes;
16377     },
16378
16379     /**
16380      * Finds the index of the passed node
16381      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16382      * @return {Number} The index of the node or -1
16383      */
16384     indexOf : function(node){
16385         node = this.getNode(node);
16386         if(typeof node.nodeIndex == "number"){
16387             return node.nodeIndex;
16388         }
16389         var ns = this.nodes;
16390         for(var i = 0, len = ns.length; i < len; i++){
16391             if(ns[i] == node){
16392                 return i;
16393             }
16394         }
16395         return -1;
16396     }
16397 });
16398 /*
16399  * - LGPL
16400  *
16401  * based on jquery fullcalendar
16402  * 
16403  */
16404
16405 Roo.bootstrap = Roo.bootstrap || {};
16406 /**
16407  * @class Roo.bootstrap.Calendar
16408  * @extends Roo.bootstrap.Component
16409  * Bootstrap Calendar class
16410  * @cfg {Boolean} loadMask (true|false) default false
16411  * @cfg {Object} header generate the user specific header of the calendar, default false
16412
16413  * @constructor
16414  * Create a new Container
16415  * @param {Object} config The config object
16416  */
16417
16418
16419
16420 Roo.bootstrap.Calendar = function(config){
16421     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16422      this.addEvents({
16423         /**
16424              * @event select
16425              * Fires when a date is selected
16426              * @param {DatePicker} this
16427              * @param {Date} date The selected date
16428              */
16429         'select': true,
16430         /**
16431              * @event monthchange
16432              * Fires when the displayed month changes 
16433              * @param {DatePicker} this
16434              * @param {Date} date The selected month
16435              */
16436         'monthchange': true,
16437         /**
16438              * @event evententer
16439              * Fires when mouse over an event
16440              * @param {Calendar} this
16441              * @param {event} Event
16442              */
16443         'evententer': true,
16444         /**
16445              * @event eventleave
16446              * Fires when the mouse leaves an
16447              * @param {Calendar} this
16448              * @param {event}
16449              */
16450         'eventleave': true,
16451         /**
16452              * @event eventclick
16453              * Fires when the mouse click an
16454              * @param {Calendar} this
16455              * @param {event}
16456              */
16457         'eventclick': true
16458         
16459     });
16460
16461 };
16462
16463 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16464     
16465      /**
16466      * @cfg {Number} startDay
16467      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16468      */
16469     startDay : 0,
16470     
16471     loadMask : false,
16472     
16473     header : false,
16474       
16475     getAutoCreate : function(){
16476         
16477         
16478         var fc_button = function(name, corner, style, content ) {
16479             return Roo.apply({},{
16480                 tag : 'span',
16481                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16482                          (corner.length ?
16483                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16484                             ''
16485                         ),
16486                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16487                 unselectable: 'on'
16488             });
16489         };
16490         
16491         var header = {};
16492         
16493         if(!this.header){
16494             header = {
16495                 tag : 'table',
16496                 cls : 'fc-header',
16497                 style : 'width:100%',
16498                 cn : [
16499                     {
16500                         tag: 'tr',
16501                         cn : [
16502                             {
16503                                 tag : 'td',
16504                                 cls : 'fc-header-left',
16505                                 cn : [
16506                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16507                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16508                                     { tag: 'span', cls: 'fc-header-space' },
16509                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16510
16511
16512                                 ]
16513                             },
16514
16515                             {
16516                                 tag : 'td',
16517                                 cls : 'fc-header-center',
16518                                 cn : [
16519                                     {
16520                                         tag: 'span',
16521                                         cls: 'fc-header-title',
16522                                         cn : {
16523                                             tag: 'H2',
16524                                             html : 'month / year'
16525                                         }
16526                                     }
16527
16528                                 ]
16529                             },
16530                             {
16531                                 tag : 'td',
16532                                 cls : 'fc-header-right',
16533                                 cn : [
16534                               /*      fc_button('month', 'left', '', 'month' ),
16535                                     fc_button('week', '', '', 'week' ),
16536                                     fc_button('day', 'right', '', 'day' )
16537                                 */    
16538
16539                                 ]
16540                             }
16541
16542                         ]
16543                     }
16544                 ]
16545             };
16546         }
16547         
16548         header = this.header;
16549         
16550        
16551         var cal_heads = function() {
16552             var ret = [];
16553             // fixme - handle this.
16554             
16555             for (var i =0; i < Date.dayNames.length; i++) {
16556                 var d = Date.dayNames[i];
16557                 ret.push({
16558                     tag: 'th',
16559                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16560                     html : d.substring(0,3)
16561                 });
16562                 
16563             }
16564             ret[0].cls += ' fc-first';
16565             ret[6].cls += ' fc-last';
16566             return ret;
16567         };
16568         var cal_cell = function(n) {
16569             return  {
16570                 tag: 'td',
16571                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16572                 cn : [
16573                     {
16574                         cn : [
16575                             {
16576                                 cls: 'fc-day-number',
16577                                 html: 'D'
16578                             },
16579                             {
16580                                 cls: 'fc-day-content',
16581                              
16582                                 cn : [
16583                                      {
16584                                         style: 'position: relative;' // height: 17px;
16585                                     }
16586                                 ]
16587                             }
16588                             
16589                             
16590                         ]
16591                     }
16592                 ]
16593                 
16594             }
16595         };
16596         var cal_rows = function() {
16597             
16598             var ret = [];
16599             for (var r = 0; r < 6; r++) {
16600                 var row= {
16601                     tag : 'tr',
16602                     cls : 'fc-week',
16603                     cn : []
16604                 };
16605                 
16606                 for (var i =0; i < Date.dayNames.length; i++) {
16607                     var d = Date.dayNames[i];
16608                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16609
16610                 }
16611                 row.cn[0].cls+=' fc-first';
16612                 row.cn[0].cn[0].style = 'min-height:90px';
16613                 row.cn[6].cls+=' fc-last';
16614                 ret.push(row);
16615                 
16616             }
16617             ret[0].cls += ' fc-first';
16618             ret[4].cls += ' fc-prev-last';
16619             ret[5].cls += ' fc-last';
16620             return ret;
16621             
16622         };
16623         
16624         var cal_table = {
16625             tag: 'table',
16626             cls: 'fc-border-separate',
16627             style : 'width:100%',
16628             cellspacing  : 0,
16629             cn : [
16630                 { 
16631                     tag: 'thead',
16632                     cn : [
16633                         { 
16634                             tag: 'tr',
16635                             cls : 'fc-first fc-last',
16636                             cn : cal_heads()
16637                         }
16638                     ]
16639                 },
16640                 { 
16641                     tag: 'tbody',
16642                     cn : cal_rows()
16643                 }
16644                   
16645             ]
16646         };
16647          
16648          var cfg = {
16649             cls : 'fc fc-ltr',
16650             cn : [
16651                 header,
16652                 {
16653                     cls : 'fc-content',
16654                     style : "position: relative;",
16655                     cn : [
16656                         {
16657                             cls : 'fc-view fc-view-month fc-grid',
16658                             style : 'position: relative',
16659                             unselectable : 'on',
16660                             cn : [
16661                                 {
16662                                     cls : 'fc-event-container',
16663                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16664                                 },
16665                                 cal_table
16666                             ]
16667                         }
16668                     ]
16669     
16670                 }
16671            ] 
16672             
16673         };
16674         
16675          
16676         
16677         return cfg;
16678     },
16679     
16680     
16681     initEvents : function()
16682     {
16683         if(!this.store){
16684             throw "can not find store for calendar";
16685         }
16686         
16687         var mark = {
16688             tag: "div",
16689             cls:"x-dlg-mask",
16690             style: "text-align:center",
16691             cn: [
16692                 {
16693                     tag: "div",
16694                     style: "background-color:white;width:50%;margin:250 auto",
16695                     cn: [
16696                         {
16697                             tag: "img",
16698                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16699                         },
16700                         {
16701                             tag: "span",
16702                             html: "Loading"
16703                         }
16704                         
16705                     ]
16706                 }
16707             ]
16708         };
16709         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16710         
16711         var size = this.el.select('.fc-content', true).first().getSize();
16712         this.maskEl.setSize(size.width, size.height);
16713         this.maskEl.enableDisplayMode("block");
16714         if(!this.loadMask){
16715             this.maskEl.hide();
16716         }
16717         
16718         this.store = Roo.factory(this.store, Roo.data);
16719         this.store.on('load', this.onLoad, this);
16720         this.store.on('beforeload', this.onBeforeLoad, this);
16721         
16722         this.resize();
16723         
16724         this.cells = this.el.select('.fc-day',true);
16725         //Roo.log(this.cells);
16726         this.textNodes = this.el.query('.fc-day-number');
16727         this.cells.addClassOnOver('fc-state-hover');
16728         
16729         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16730         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16731         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16732         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16733         
16734         this.on('monthchange', this.onMonthChange, this);
16735         
16736         this.update(new Date().clearTime());
16737     },
16738     
16739     resize : function() {
16740         var sz  = this.el.getSize();
16741         
16742         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16743         this.el.select('.fc-day-content div',true).setHeight(34);
16744     },
16745     
16746     
16747     // private
16748     showPrevMonth : function(e){
16749         this.update(this.activeDate.add("mo", -1));
16750     },
16751     showToday : function(e){
16752         this.update(new Date().clearTime());
16753     },
16754     // private
16755     showNextMonth : function(e){
16756         this.update(this.activeDate.add("mo", 1));
16757     },
16758
16759     // private
16760     showPrevYear : function(){
16761         this.update(this.activeDate.add("y", -1));
16762     },
16763
16764     // private
16765     showNextYear : function(){
16766         this.update(this.activeDate.add("y", 1));
16767     },
16768
16769     
16770    // private
16771     update : function(date)
16772     {
16773         var vd = this.activeDate;
16774         this.activeDate = date;
16775 //        if(vd && this.el){
16776 //            var t = date.getTime();
16777 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16778 //                Roo.log('using add remove');
16779 //                
16780 //                this.fireEvent('monthchange', this, date);
16781 //                
16782 //                this.cells.removeClass("fc-state-highlight");
16783 //                this.cells.each(function(c){
16784 //                   if(c.dateValue == t){
16785 //                       c.addClass("fc-state-highlight");
16786 //                       setTimeout(function(){
16787 //                            try{c.dom.firstChild.focus();}catch(e){}
16788 //                       }, 50);
16789 //                       return false;
16790 //                   }
16791 //                   return true;
16792 //                });
16793 //                return;
16794 //            }
16795 //        }
16796         
16797         var days = date.getDaysInMonth();
16798         
16799         var firstOfMonth = date.getFirstDateOfMonth();
16800         var startingPos = firstOfMonth.getDay()-this.startDay;
16801         
16802         if(startingPos < this.startDay){
16803             startingPos += 7;
16804         }
16805         
16806         var pm = date.add(Date.MONTH, -1);
16807         var prevStart = pm.getDaysInMonth()-startingPos;
16808 //        
16809         this.cells = this.el.select('.fc-day',true);
16810         this.textNodes = this.el.query('.fc-day-number');
16811         this.cells.addClassOnOver('fc-state-hover');
16812         
16813         var cells = this.cells.elements;
16814         var textEls = this.textNodes;
16815         
16816         Roo.each(cells, function(cell){
16817             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16818         });
16819         
16820         days += startingPos;
16821
16822         // convert everything to numbers so it's fast
16823         var day = 86400000;
16824         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16825         //Roo.log(d);
16826         //Roo.log(pm);
16827         //Roo.log(prevStart);
16828         
16829         var today = new Date().clearTime().getTime();
16830         var sel = date.clearTime().getTime();
16831         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16832         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16833         var ddMatch = this.disabledDatesRE;
16834         var ddText = this.disabledDatesText;
16835         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16836         var ddaysText = this.disabledDaysText;
16837         var format = this.format;
16838         
16839         var setCellClass = function(cal, cell){
16840             cell.row = 0;
16841             cell.events = [];
16842             cell.more = [];
16843             //Roo.log('set Cell Class');
16844             cell.title = "";
16845             var t = d.getTime();
16846             
16847             //Roo.log(d);
16848             
16849             cell.dateValue = t;
16850             if(t == today){
16851                 cell.className += " fc-today";
16852                 cell.className += " fc-state-highlight";
16853                 cell.title = cal.todayText;
16854             }
16855             if(t == sel){
16856                 // disable highlight in other month..
16857                 //cell.className += " fc-state-highlight";
16858                 
16859             }
16860             // disabling
16861             if(t < min) {
16862                 cell.className = " fc-state-disabled";
16863                 cell.title = cal.minText;
16864                 return;
16865             }
16866             if(t > max) {
16867                 cell.className = " fc-state-disabled";
16868                 cell.title = cal.maxText;
16869                 return;
16870             }
16871             if(ddays){
16872                 if(ddays.indexOf(d.getDay()) != -1){
16873                     cell.title = ddaysText;
16874                     cell.className = " fc-state-disabled";
16875                 }
16876             }
16877             if(ddMatch && format){
16878                 var fvalue = d.dateFormat(format);
16879                 if(ddMatch.test(fvalue)){
16880                     cell.title = ddText.replace("%0", fvalue);
16881                     cell.className = " fc-state-disabled";
16882                 }
16883             }
16884             
16885             if (!cell.initialClassName) {
16886                 cell.initialClassName = cell.dom.className;
16887             }
16888             
16889             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16890         };
16891
16892         var i = 0;
16893         
16894         for(; i < startingPos; i++) {
16895             textEls[i].innerHTML = (++prevStart);
16896             d.setDate(d.getDate()+1);
16897             
16898             cells[i].className = "fc-past fc-other-month";
16899             setCellClass(this, cells[i]);
16900         }
16901         
16902         var intDay = 0;
16903         
16904         for(; i < days; i++){
16905             intDay = i - startingPos + 1;
16906             textEls[i].innerHTML = (intDay);
16907             d.setDate(d.getDate()+1);
16908             
16909             cells[i].className = ''; // "x-date-active";
16910             setCellClass(this, cells[i]);
16911         }
16912         var extraDays = 0;
16913         
16914         for(; i < 42; i++) {
16915             textEls[i].innerHTML = (++extraDays);
16916             d.setDate(d.getDate()+1);
16917             
16918             cells[i].className = "fc-future fc-other-month";
16919             setCellClass(this, cells[i]);
16920         }
16921         
16922         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16923         
16924         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16925         
16926         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16927         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16928         
16929         if(totalRows != 6){
16930             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16931             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16932         }
16933         
16934         this.fireEvent('monthchange', this, date);
16935         
16936         
16937         /*
16938         if(!this.internalRender){
16939             var main = this.el.dom.firstChild;
16940             var w = main.offsetWidth;
16941             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16942             Roo.fly(main).setWidth(w);
16943             this.internalRender = true;
16944             // opera does not respect the auto grow header center column
16945             // then, after it gets a width opera refuses to recalculate
16946             // without a second pass
16947             if(Roo.isOpera && !this.secondPass){
16948                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16949                 this.secondPass = true;
16950                 this.update.defer(10, this, [date]);
16951             }
16952         }
16953         */
16954         
16955     },
16956     
16957     findCell : function(dt) {
16958         dt = dt.clearTime().getTime();
16959         var ret = false;
16960         this.cells.each(function(c){
16961             //Roo.log("check " +c.dateValue + '?=' + dt);
16962             if(c.dateValue == dt){
16963                 ret = c;
16964                 return false;
16965             }
16966             return true;
16967         });
16968         
16969         return ret;
16970     },
16971     
16972     findCells : function(ev) {
16973         var s = ev.start.clone().clearTime().getTime();
16974        // Roo.log(s);
16975         var e= ev.end.clone().clearTime().getTime();
16976        // Roo.log(e);
16977         var ret = [];
16978         this.cells.each(function(c){
16979              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16980             
16981             if(c.dateValue > e){
16982                 return ;
16983             }
16984             if(c.dateValue < s){
16985                 return ;
16986             }
16987             ret.push(c);
16988         });
16989         
16990         return ret;    
16991     },
16992     
16993 //    findBestRow: function(cells)
16994 //    {
16995 //        var ret = 0;
16996 //        
16997 //        for (var i =0 ; i < cells.length;i++) {
16998 //            ret  = Math.max(cells[i].rows || 0,ret);
16999 //        }
17000 //        return ret;
17001 //        
17002 //    },
17003     
17004     
17005     addItem : function(ev)
17006     {
17007         // look for vertical location slot in
17008         var cells = this.findCells(ev);
17009         
17010 //        ev.row = this.findBestRow(cells);
17011         
17012         // work out the location.
17013         
17014         var crow = false;
17015         var rows = [];
17016         for(var i =0; i < cells.length; i++) {
17017             
17018             cells[i].row = cells[0].row;
17019             
17020             if(i == 0){
17021                 cells[i].row = cells[i].row + 1;
17022             }
17023             
17024             if (!crow) {
17025                 crow = {
17026                     start : cells[i],
17027                     end :  cells[i]
17028                 };
17029                 continue;
17030             }
17031             if (crow.start.getY() == cells[i].getY()) {
17032                 // on same row.
17033                 crow.end = cells[i];
17034                 continue;
17035             }
17036             // different row.
17037             rows.push(crow);
17038             crow = {
17039                 start: cells[i],
17040                 end : cells[i]
17041             };
17042             
17043         }
17044         
17045         rows.push(crow);
17046         ev.els = [];
17047         ev.rows = rows;
17048         ev.cells = cells;
17049         
17050         cells[0].events.push(ev);
17051         
17052         this.calevents.push(ev);
17053     },
17054     
17055     clearEvents: function() {
17056         
17057         if(!this.calevents){
17058             return;
17059         }
17060         
17061         Roo.each(this.cells.elements, function(c){
17062             c.row = 0;
17063             c.events = [];
17064             c.more = [];
17065         });
17066         
17067         Roo.each(this.calevents, function(e) {
17068             Roo.each(e.els, function(el) {
17069                 el.un('mouseenter' ,this.onEventEnter, this);
17070                 el.un('mouseleave' ,this.onEventLeave, this);
17071                 el.remove();
17072             },this);
17073         },this);
17074         
17075         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17076             e.remove();
17077         });
17078         
17079     },
17080     
17081     renderEvents: function()
17082     {   
17083         var _this = this;
17084         
17085         this.cells.each(function(c) {
17086             
17087             if(c.row < 5){
17088                 return;
17089             }
17090             
17091             var ev = c.events;
17092             
17093             var r = 4;
17094             if(c.row != c.events.length){
17095                 r = 4 - (4 - (c.row - c.events.length));
17096             }
17097             
17098             c.events = ev.slice(0, r);
17099             c.more = ev.slice(r);
17100             
17101             if(c.more.length && c.more.length == 1){
17102                 c.events.push(c.more.pop());
17103             }
17104             
17105             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17106             
17107         });
17108             
17109         this.cells.each(function(c) {
17110             
17111             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17112             
17113             
17114             for (var e = 0; e < c.events.length; e++){
17115                 var ev = c.events[e];
17116                 var rows = ev.rows;
17117                 
17118                 for(var i = 0; i < rows.length; i++) {
17119                 
17120                     // how many rows should it span..
17121
17122                     var  cfg = {
17123                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17124                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17125
17126                         unselectable : "on",
17127                         cn : [
17128                             {
17129                                 cls: 'fc-event-inner',
17130                                 cn : [
17131     //                                {
17132     //                                  tag:'span',
17133     //                                  cls: 'fc-event-time',
17134     //                                  html : cells.length > 1 ? '' : ev.time
17135     //                                },
17136                                     {
17137                                       tag:'span',
17138                                       cls: 'fc-event-title',
17139                                       html : String.format('{0}', ev.title)
17140                                     }
17141
17142
17143                                 ]
17144                             },
17145                             {
17146                                 cls: 'ui-resizable-handle ui-resizable-e',
17147                                 html : '&nbsp;&nbsp;&nbsp'
17148                             }
17149
17150                         ]
17151                     };
17152
17153                     if (i == 0) {
17154                         cfg.cls += ' fc-event-start';
17155                     }
17156                     if ((i+1) == rows.length) {
17157                         cfg.cls += ' fc-event-end';
17158                     }
17159
17160                     var ctr = _this.el.select('.fc-event-container',true).first();
17161                     var cg = ctr.createChild(cfg);
17162
17163                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17164                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17165
17166                     var r = (c.more.length) ? 1 : 0;
17167                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17168                     cg.setWidth(ebox.right - sbox.x -2);
17169
17170                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17171                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17172                     cg.on('click', _this.onEventClick, _this, ev);
17173
17174                     ev.els.push(cg);
17175                     
17176                 }
17177                 
17178             }
17179             
17180             
17181             if(c.more.length){
17182                 var  cfg = {
17183                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17184                     style : 'position: absolute',
17185                     unselectable : "on",
17186                     cn : [
17187                         {
17188                             cls: 'fc-event-inner',
17189                             cn : [
17190                                 {
17191                                   tag:'span',
17192                                   cls: 'fc-event-title',
17193                                   html : 'More'
17194                                 }
17195
17196
17197                             ]
17198                         },
17199                         {
17200                             cls: 'ui-resizable-handle ui-resizable-e',
17201                             html : '&nbsp;&nbsp;&nbsp'
17202                         }
17203
17204                     ]
17205                 };
17206
17207                 var ctr = _this.el.select('.fc-event-container',true).first();
17208                 var cg = ctr.createChild(cfg);
17209
17210                 var sbox = c.select('.fc-day-content',true).first().getBox();
17211                 var ebox = c.select('.fc-day-content',true).first().getBox();
17212                 //Roo.log(cg);
17213                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17214                 cg.setWidth(ebox.right - sbox.x -2);
17215
17216                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17217                 
17218             }
17219             
17220         });
17221         
17222         
17223         
17224     },
17225     
17226     onEventEnter: function (e, el,event,d) {
17227         this.fireEvent('evententer', this, el, event);
17228     },
17229     
17230     onEventLeave: function (e, el,event,d) {
17231         this.fireEvent('eventleave', this, el, event);
17232     },
17233     
17234     onEventClick: function (e, el,event,d) {
17235         this.fireEvent('eventclick', this, el, event);
17236     },
17237     
17238     onMonthChange: function () {
17239         this.store.load();
17240     },
17241     
17242     onMoreEventClick: function(e, el, more)
17243     {
17244         var _this = this;
17245         
17246         this.calpopover.placement = 'right';
17247         this.calpopover.setTitle('More');
17248         
17249         this.calpopover.setContent('');
17250         
17251         var ctr = this.calpopover.el.select('.popover-content', true).first();
17252         
17253         Roo.each(more, function(m){
17254             var cfg = {
17255                 cls : 'fc-event-hori fc-event-draggable',
17256                 html : m.title
17257             };
17258             var cg = ctr.createChild(cfg);
17259             
17260             cg.on('click', _this.onEventClick, _this, m);
17261         });
17262         
17263         this.calpopover.show(el);
17264         
17265         
17266     },
17267     
17268     onLoad: function () 
17269     {   
17270         this.calevents = [];
17271         var cal = this;
17272         
17273         if(this.store.getCount() > 0){
17274             this.store.data.each(function(d){
17275                cal.addItem({
17276                     id : d.data.id,
17277                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17278                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17279                     time : d.data.start_time,
17280                     title : d.data.title,
17281                     description : d.data.description,
17282                     venue : d.data.venue
17283                 });
17284             });
17285         }
17286         
17287         this.renderEvents();
17288         
17289         if(this.calevents.length && this.loadMask){
17290             this.maskEl.hide();
17291         }
17292     },
17293     
17294     onBeforeLoad: function()
17295     {
17296         this.clearEvents();
17297         if(this.loadMask){
17298             this.maskEl.show();
17299         }
17300     }
17301 });
17302
17303  
17304  /*
17305  * - LGPL
17306  *
17307  * element
17308  * 
17309  */
17310
17311 /**
17312  * @class Roo.bootstrap.Popover
17313  * @extends Roo.bootstrap.Component
17314  * Bootstrap Popover class
17315  * @cfg {String} html contents of the popover   (or false to use children..)
17316  * @cfg {String} title of popover (or false to hide)
17317  * @cfg {String} placement how it is placed
17318  * @cfg {String} trigger click || hover (or false to trigger manually)
17319  * @cfg {String} over what (parent or false to trigger manually.)
17320  * @cfg {Number} delay - delay before showing
17321  
17322  * @constructor
17323  * Create a new Popover
17324  * @param {Object} config The config object
17325  */
17326
17327 Roo.bootstrap.Popover = function(config){
17328     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17329     
17330     this.addEvents({
17331         // raw events
17332          /**
17333          * @event show
17334          * After the popover show
17335          * 
17336          * @param {Roo.bootstrap.Popover} this
17337          */
17338         "show" : true,
17339         /**
17340          * @event hide
17341          * After the popover hide
17342          * 
17343          * @param {Roo.bootstrap.Popover} this
17344          */
17345         "hide" : true
17346     });
17347 };
17348
17349 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17350     
17351     title: 'Fill in a title',
17352     html: false,
17353     
17354     placement : 'right',
17355     trigger : 'hover', // hover
17356     
17357     delay : 0,
17358     
17359     over: 'parent',
17360     
17361     can_build_overlaid : false,
17362     
17363     getChildContainer : function()
17364     {
17365         return this.el.select('.popover-content',true).first();
17366     },
17367     
17368     getAutoCreate : function(){
17369          
17370         var cfg = {
17371            cls : 'popover roo-dynamic',
17372            style: 'display:block',
17373            cn : [
17374                 {
17375                     cls : 'arrow'
17376                 },
17377                 {
17378                     cls : 'popover-inner',
17379                     cn : [
17380                         {
17381                             tag: 'h3',
17382                             cls: 'popover-title',
17383                             html : this.title
17384                         },
17385                         {
17386                             cls : 'popover-content',
17387                             html : this.html
17388                         }
17389                     ]
17390                     
17391                 }
17392            ]
17393         };
17394         
17395         return cfg;
17396     },
17397     setTitle: function(str)
17398     {
17399         this.title = str;
17400         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17401     },
17402     setContent: function(str)
17403     {
17404         this.html = str;
17405         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17406     },
17407     // as it get's added to the bottom of the page.
17408     onRender : function(ct, position)
17409     {
17410         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17411         if(!this.el){
17412             var cfg = Roo.apply({},  this.getAutoCreate());
17413             cfg.id = Roo.id();
17414             
17415             if (this.cls) {
17416                 cfg.cls += ' ' + this.cls;
17417             }
17418             if (this.style) {
17419                 cfg.style = this.style;
17420             }
17421             //Roo.log("adding to ");
17422             this.el = Roo.get(document.body).createChild(cfg, position);
17423 //            Roo.log(this.el);
17424         }
17425         this.initEvents();
17426     },
17427     
17428     initEvents : function()
17429     {
17430         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17431         this.el.enableDisplayMode('block');
17432         this.el.hide();
17433         if (this.over === false) {
17434             return; 
17435         }
17436         if (this.triggers === false) {
17437             return;
17438         }
17439         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17440         var triggers = this.trigger ? this.trigger.split(' ') : [];
17441         Roo.each(triggers, function(trigger) {
17442         
17443             if (trigger == 'click') {
17444                 on_el.on('click', this.toggle, this);
17445             } else if (trigger != 'manual') {
17446                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17447                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17448       
17449                 on_el.on(eventIn  ,this.enter, this);
17450                 on_el.on(eventOut, this.leave, this);
17451             }
17452         }, this);
17453         
17454     },
17455     
17456     
17457     // private
17458     timeout : null,
17459     hoverState : null,
17460     
17461     toggle : function () {
17462         this.hoverState == 'in' ? this.leave() : this.enter();
17463     },
17464     
17465     enter : function () {
17466         
17467         clearTimeout(this.timeout);
17468     
17469         this.hoverState = 'in';
17470     
17471         if (!this.delay || !this.delay.show) {
17472             this.show();
17473             return;
17474         }
17475         var _t = this;
17476         this.timeout = setTimeout(function () {
17477             if (_t.hoverState == 'in') {
17478                 _t.show();
17479             }
17480         }, this.delay.show)
17481     },
17482     
17483     leave : function() {
17484         clearTimeout(this.timeout);
17485     
17486         this.hoverState = 'out';
17487     
17488         if (!this.delay || !this.delay.hide) {
17489             this.hide();
17490             return;
17491         }
17492         var _t = this;
17493         this.timeout = setTimeout(function () {
17494             if (_t.hoverState == 'out') {
17495                 _t.hide();
17496             }
17497         }, this.delay.hide)
17498     },
17499     
17500     show : function (on_el)
17501     {
17502         if (!on_el) {
17503             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17504         }
17505         
17506         // set content.
17507         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17508         if (this.html !== false) {
17509             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17510         }
17511         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17512         if (!this.title.length) {
17513             this.el.select('.popover-title',true).hide();
17514         }
17515         
17516         var placement = typeof this.placement == 'function' ?
17517             this.placement.call(this, this.el, on_el) :
17518             this.placement;
17519             
17520         var autoToken = /\s?auto?\s?/i;
17521         var autoPlace = autoToken.test(placement);
17522         if (autoPlace) {
17523             placement = placement.replace(autoToken, '') || 'top';
17524         }
17525         
17526         //this.el.detach()
17527         //this.el.setXY([0,0]);
17528         this.el.show();
17529         this.el.dom.style.display='block';
17530         this.el.addClass(placement);
17531         
17532         //this.el.appendTo(on_el);
17533         
17534         var p = this.getPosition();
17535         var box = this.el.getBox();
17536         
17537         if (autoPlace) {
17538             // fixme..
17539         }
17540         var align = Roo.bootstrap.Popover.alignment[placement];
17541         
17542 //        Roo.log(align);
17543         this.el.alignTo(on_el, align[0],align[1]);
17544         //var arrow = this.el.select('.arrow',true).first();
17545         //arrow.set(align[2], 
17546         
17547         this.el.addClass('in');
17548         
17549         
17550         if (this.el.hasClass('fade')) {
17551             // fade it?
17552         }
17553         
17554         this.hoverState = 'in';
17555         
17556         this.fireEvent('show', this);
17557         
17558     },
17559     hide : function()
17560     {
17561         this.el.setXY([0,0]);
17562         this.el.removeClass('in');
17563         this.el.hide();
17564         this.hoverState = null;
17565         
17566         this.fireEvent('hide', this);
17567     }
17568     
17569 });
17570
17571 Roo.bootstrap.Popover.alignment = {
17572     'left' : ['r-l', [-10,0], 'right'],
17573     'right' : ['l-r', [10,0], 'left'],
17574     'bottom' : ['t-b', [0,10], 'top'],
17575     'top' : [ 'b-t', [0,-10], 'bottom']
17576 };
17577
17578  /*
17579  * - LGPL
17580  *
17581  * Progress
17582  * 
17583  */
17584
17585 /**
17586  * @class Roo.bootstrap.Progress
17587  * @extends Roo.bootstrap.Component
17588  * Bootstrap Progress class
17589  * @cfg {Boolean} striped striped of the progress bar
17590  * @cfg {Boolean} active animated of the progress bar
17591  * 
17592  * 
17593  * @constructor
17594  * Create a new Progress
17595  * @param {Object} config The config object
17596  */
17597
17598 Roo.bootstrap.Progress = function(config){
17599     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17600 };
17601
17602 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17603     
17604     striped : false,
17605     active: false,
17606     
17607     getAutoCreate : function(){
17608         var cfg = {
17609             tag: 'div',
17610             cls: 'progress'
17611         };
17612         
17613         
17614         if(this.striped){
17615             cfg.cls += ' progress-striped';
17616         }
17617       
17618         if(this.active){
17619             cfg.cls += ' active';
17620         }
17621         
17622         
17623         return cfg;
17624     }
17625    
17626 });
17627
17628  
17629
17630  /*
17631  * - LGPL
17632  *
17633  * ProgressBar
17634  * 
17635  */
17636
17637 /**
17638  * @class Roo.bootstrap.ProgressBar
17639  * @extends Roo.bootstrap.Component
17640  * Bootstrap ProgressBar class
17641  * @cfg {Number} aria_valuenow aria-value now
17642  * @cfg {Number} aria_valuemin aria-value min
17643  * @cfg {Number} aria_valuemax aria-value max
17644  * @cfg {String} label label for the progress bar
17645  * @cfg {String} panel (success | info | warning | danger )
17646  * @cfg {String} role role of the progress bar
17647  * @cfg {String} sr_only text
17648  * 
17649  * 
17650  * @constructor
17651  * Create a new ProgressBar
17652  * @param {Object} config The config object
17653  */
17654
17655 Roo.bootstrap.ProgressBar = function(config){
17656     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17657 };
17658
17659 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17660     
17661     aria_valuenow : 0,
17662     aria_valuemin : 0,
17663     aria_valuemax : 100,
17664     label : false,
17665     panel : false,
17666     role : false,
17667     sr_only: false,
17668     
17669     getAutoCreate : function()
17670     {
17671         
17672         var cfg = {
17673             tag: 'div',
17674             cls: 'progress-bar',
17675             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17676         };
17677         
17678         if(this.sr_only){
17679             cfg.cn = {
17680                 tag: 'span',
17681                 cls: 'sr-only',
17682                 html: this.sr_only
17683             }
17684         }
17685         
17686         if(this.role){
17687             cfg.role = this.role;
17688         }
17689         
17690         if(this.aria_valuenow){
17691             cfg['aria-valuenow'] = this.aria_valuenow;
17692         }
17693         
17694         if(this.aria_valuemin){
17695             cfg['aria-valuemin'] = this.aria_valuemin;
17696         }
17697         
17698         if(this.aria_valuemax){
17699             cfg['aria-valuemax'] = this.aria_valuemax;
17700         }
17701         
17702         if(this.label && !this.sr_only){
17703             cfg.html = this.label;
17704         }
17705         
17706         if(this.panel){
17707             cfg.cls += ' progress-bar-' + this.panel;
17708         }
17709         
17710         return cfg;
17711     },
17712     
17713     update : function(aria_valuenow)
17714     {
17715         this.aria_valuenow = aria_valuenow;
17716         
17717         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17718     }
17719    
17720 });
17721
17722  
17723
17724  /*
17725  * - LGPL
17726  *
17727  * column
17728  * 
17729  */
17730
17731 /**
17732  * @class Roo.bootstrap.TabGroup
17733  * @extends Roo.bootstrap.Column
17734  * Bootstrap Column class
17735  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17736  * @cfg {Boolean} carousel true to make the group behave like a carousel
17737  * @cfg {Boolean} bullets show bullets for the panels
17738  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17739  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17740  * @cfg {Boolean} showarrow (true|false) show arrow default true
17741  * 
17742  * @constructor
17743  * Create a new TabGroup
17744  * @param {Object} config The config object
17745  */
17746
17747 Roo.bootstrap.TabGroup = function(config){
17748     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17749     if (!this.navId) {
17750         this.navId = Roo.id();
17751     }
17752     this.tabs = [];
17753     Roo.bootstrap.TabGroup.register(this);
17754     
17755 };
17756
17757 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17758     
17759     carousel : false,
17760     transition : false,
17761     bullets : 0,
17762     timer : 0,
17763     autoslide : false,
17764     slideFn : false,
17765     slideOnTouch : false,
17766     showarrow : true,
17767     
17768     getAutoCreate : function()
17769     {
17770         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17771         
17772         cfg.cls += ' tab-content';
17773         
17774         if (this.carousel) {
17775             cfg.cls += ' carousel slide';
17776             
17777             cfg.cn = [{
17778                cls : 'carousel-inner',
17779                cn : []
17780             }];
17781         
17782             if(this.bullets  && !Roo.isTouch){
17783                 
17784                 var bullets = {
17785                     cls : 'carousel-bullets',
17786                     cn : []
17787                 };
17788                
17789                 if(this.bullets_cls){
17790                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17791                 }
17792                 
17793                 bullets.cn.push({
17794                     cls : 'clear'
17795                 });
17796                 
17797                 cfg.cn[0].cn.push(bullets);
17798             }
17799             
17800             if(this.showarrow){
17801                 cfg.cn[0].cn.push({
17802                     tag : 'div',
17803                     class : 'carousel-arrow',
17804                     cn : [
17805                         {
17806                             tag : 'div',
17807                             class : 'carousel-prev',
17808                             cn : [
17809                                 {
17810                                     tag : 'i',
17811                                     class : 'fa fa-chevron-left'
17812                                 }
17813                             ]
17814                         },
17815                         {
17816                             tag : 'div',
17817                             class : 'carousel-next',
17818                             cn : [
17819                                 {
17820                                     tag : 'i',
17821                                     class : 'fa fa-chevron-right'
17822                                 }
17823                             ]
17824                         }
17825                     ]
17826                 });
17827             }
17828             
17829         }
17830         
17831         return cfg;
17832     },
17833     
17834     initEvents:  function()
17835     {
17836 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17837 //            this.el.on("touchstart", this.onTouchStart, this);
17838 //        }
17839         
17840         if(this.autoslide){
17841             var _this = this;
17842             
17843             this.slideFn = window.setInterval(function() {
17844                 _this.showPanelNext();
17845             }, this.timer);
17846         }
17847         
17848         if(this.showarrow){
17849             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17850             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17851         }
17852         
17853         
17854     },
17855     
17856 //    onTouchStart : function(e, el, o)
17857 //    {
17858 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17859 //            return;
17860 //        }
17861 //        
17862 //        this.showPanelNext();
17863 //    },
17864     
17865     
17866     getChildContainer : function()
17867     {
17868         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17869     },
17870     
17871     /**
17872     * register a Navigation item
17873     * @param {Roo.bootstrap.NavItem} the navitem to add
17874     */
17875     register : function(item)
17876     {
17877         this.tabs.push( item);
17878         item.navId = this.navId; // not really needed..
17879         this.addBullet();
17880     
17881     },
17882     
17883     getActivePanel : function()
17884     {
17885         var r = false;
17886         Roo.each(this.tabs, function(t) {
17887             if (t.active) {
17888                 r = t;
17889                 return false;
17890             }
17891             return null;
17892         });
17893         return r;
17894         
17895     },
17896     getPanelByName : function(n)
17897     {
17898         var r = false;
17899         Roo.each(this.tabs, function(t) {
17900             if (t.tabId == n) {
17901                 r = t;
17902                 return false;
17903             }
17904             return null;
17905         });
17906         return r;
17907     },
17908     indexOfPanel : function(p)
17909     {
17910         var r = false;
17911         Roo.each(this.tabs, function(t,i) {
17912             if (t.tabId == p.tabId) {
17913                 r = i;
17914                 return false;
17915             }
17916             return null;
17917         });
17918         return r;
17919     },
17920     /**
17921      * show a specific panel
17922      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17923      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17924      */
17925     showPanel : function (pan)
17926     {
17927         if(this.transition || typeof(pan) == 'undefined'){
17928             Roo.log("waiting for the transitionend");
17929             return;
17930         }
17931         
17932         if (typeof(pan) == 'number') {
17933             pan = this.tabs[pan];
17934         }
17935         
17936         if (typeof(pan) == 'string') {
17937             pan = this.getPanelByName(pan);
17938         }
17939         
17940         var cur = this.getActivePanel();
17941         
17942         if(!pan || !cur){
17943             Roo.log('pan or acitve pan is undefined');
17944             return false;
17945         }
17946         
17947         if (pan.tabId == this.getActivePanel().tabId) {
17948             return true;
17949         }
17950         
17951         if (false === cur.fireEvent('beforedeactivate')) {
17952             return false;
17953         }
17954         
17955         if(this.bullets > 0 && !Roo.isTouch){
17956             this.setActiveBullet(this.indexOfPanel(pan));
17957         }
17958         
17959         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17960             
17961             this.transition = true;
17962             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
17963             var lr = dir == 'next' ? 'left' : 'right';
17964             pan.el.addClass(dir); // or prev
17965             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17966             cur.el.addClass(lr); // or right
17967             pan.el.addClass(lr);
17968             
17969             var _this = this;
17970             cur.el.on('transitionend', function() {
17971                 Roo.log("trans end?");
17972                 
17973                 pan.el.removeClass([lr,dir]);
17974                 pan.setActive(true);
17975                 
17976                 cur.el.removeClass([lr]);
17977                 cur.setActive(false);
17978                 
17979                 _this.transition = false;
17980                 
17981             }, this, { single:  true } );
17982             
17983             return true;
17984         }
17985         
17986         cur.setActive(false);
17987         pan.setActive(true);
17988         
17989         return true;
17990         
17991     },
17992     showPanelNext : function()
17993     {
17994         var i = this.indexOfPanel(this.getActivePanel());
17995         
17996         if (i >= this.tabs.length - 1 && !this.autoslide) {
17997             return;
17998         }
17999         
18000         if (i >= this.tabs.length - 1 && this.autoslide) {
18001             i = -1;
18002         }
18003         
18004         this.showPanel(this.tabs[i+1]);
18005     },
18006     
18007     showPanelPrev : function()
18008     {
18009         var i = this.indexOfPanel(this.getActivePanel());
18010         
18011         if (i  < 1 && !this.autoslide) {
18012             return;
18013         }
18014         
18015         if (i < 1 && this.autoslide) {
18016             i = this.tabs.length;
18017         }
18018         
18019         this.showPanel(this.tabs[i-1]);
18020     },
18021     
18022     
18023     addBullet: function()
18024     {
18025         if(!this.bullets || Roo.isTouch){
18026             return;
18027         }
18028         var ctr = this.el.select('.carousel-bullets',true).first();
18029         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18030         var bullet = ctr.createChild({
18031             cls : 'bullet bullet-' + i
18032         },ctr.dom.lastChild);
18033         
18034         
18035         var _this = this;
18036         
18037         bullet.on('click', (function(e, el, o, ii, t){
18038
18039             e.preventDefault();
18040
18041             this.showPanel(ii);
18042
18043             if(this.autoslide && this.slideFn){
18044                 clearInterval(this.slideFn);
18045                 this.slideFn = window.setInterval(function() {
18046                     _this.showPanelNext();
18047                 }, this.timer);
18048             }
18049
18050         }).createDelegate(this, [i, bullet], true));
18051                 
18052         
18053     },
18054      
18055     setActiveBullet : function(i)
18056     {
18057         if(Roo.isTouch){
18058             return;
18059         }
18060         
18061         Roo.each(this.el.select('.bullet', true).elements, function(el){
18062             el.removeClass('selected');
18063         });
18064
18065         var bullet = this.el.select('.bullet-' + i, true).first();
18066         
18067         if(!bullet){
18068             return;
18069         }
18070         
18071         bullet.addClass('selected');
18072     }
18073     
18074     
18075   
18076 });
18077
18078  
18079
18080  
18081  
18082 Roo.apply(Roo.bootstrap.TabGroup, {
18083     
18084     groups: {},
18085      /**
18086     * register a Navigation Group
18087     * @param {Roo.bootstrap.NavGroup} the navgroup to add
18088     */
18089     register : function(navgrp)
18090     {
18091         this.groups[navgrp.navId] = navgrp;
18092         
18093     },
18094     /**
18095     * fetch a Navigation Group based on the navigation ID
18096     * if one does not exist , it will get created.
18097     * @param {string} the navgroup to add
18098     * @returns {Roo.bootstrap.NavGroup} the navgroup 
18099     */
18100     get: function(navId) {
18101         if (typeof(this.groups[navId]) == 'undefined') {
18102             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18103         }
18104         return this.groups[navId] ;
18105     }
18106     
18107     
18108     
18109 });
18110
18111  /*
18112  * - LGPL
18113  *
18114  * TabPanel
18115  * 
18116  */
18117
18118 /**
18119  * @class Roo.bootstrap.TabPanel
18120  * @extends Roo.bootstrap.Component
18121  * Bootstrap TabPanel class
18122  * @cfg {Boolean} active panel active
18123  * @cfg {String} html panel content
18124  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18125  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18126  * @cfg {String} href click to link..
18127  * 
18128  * 
18129  * @constructor
18130  * Create a new TabPanel
18131  * @param {Object} config The config object
18132  */
18133
18134 Roo.bootstrap.TabPanel = function(config){
18135     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18136     this.addEvents({
18137         /**
18138              * @event changed
18139              * Fires when the active status changes
18140              * @param {Roo.bootstrap.TabPanel} this
18141              * @param {Boolean} state the new state
18142             
18143          */
18144         'changed': true,
18145         /**
18146              * @event beforedeactivate
18147              * Fires before a tab is de-activated - can be used to do validation on a form.
18148              * @param {Roo.bootstrap.TabPanel} this
18149              * @return {Boolean} false if there is an error
18150             
18151          */
18152         'beforedeactivate': true
18153      });
18154     
18155     this.tabId = this.tabId || Roo.id();
18156   
18157 };
18158
18159 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
18160     
18161     active: false,
18162     html: false,
18163     tabId: false,
18164     navId : false,
18165     href : '',
18166     
18167     getAutoCreate : function(){
18168         var cfg = {
18169             tag: 'div',
18170             // item is needed for carousel - not sure if it has any effect otherwise
18171             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18172             html: this.html || ''
18173         };
18174         
18175         if(this.active){
18176             cfg.cls += ' active';
18177         }
18178         
18179         if(this.tabId){
18180             cfg.tabId = this.tabId;
18181         }
18182         
18183         
18184         return cfg;
18185     },
18186     
18187     initEvents:  function()
18188     {
18189         var p = this.parent();
18190         
18191         this.navId = this.navId || p.navId;
18192         
18193         if (typeof(this.navId) != 'undefined') {
18194             // not really needed.. but just in case.. parent should be a NavGroup.
18195             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18196             
18197             tg.register(this);
18198             
18199             var i = tg.tabs.length - 1;
18200             
18201             if(this.active && tg.bullets > 0 && i < tg.bullets){
18202                 tg.setActiveBullet(i);
18203             }
18204         }
18205         
18206         this.el.on('click', this.onClick, this);
18207         
18208         if(Roo.isTouch){
18209             this.el.on("touchstart", this.onTouchStart, this);
18210             this.el.on("touchmove", this.onTouchMove, this);
18211             this.el.on("touchend", this.onTouchEnd, this);
18212         }
18213         
18214     },
18215     
18216     onRender : function(ct, position)
18217     {
18218         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18219     },
18220     
18221     setActive : function(state)
18222     {
18223         Roo.log("panel - set active " + this.tabId + "=" + state);
18224         
18225         this.active = state;
18226         if (!state) {
18227             this.el.removeClass('active');
18228             
18229         } else  if (!this.el.hasClass('active')) {
18230             this.el.addClass('active');
18231         }
18232         
18233         this.fireEvent('changed', this, state);
18234     },
18235     
18236     onClick : function(e)
18237     {
18238         e.preventDefault();
18239         
18240         if(!this.href.length){
18241             return;
18242         }
18243         
18244         window.location.href = this.href;
18245     },
18246     
18247     startX : 0,
18248     startY : 0,
18249     endX : 0,
18250     endY : 0,
18251     swiping : false,
18252     
18253     onTouchStart : function(e)
18254     {
18255         this.swiping = false;
18256         
18257         this.startX = e.browserEvent.touches[0].clientX;
18258         this.startY = e.browserEvent.touches[0].clientY;
18259     },
18260     
18261     onTouchMove : function(e)
18262     {
18263         this.swiping = true;
18264         
18265         this.endX = e.browserEvent.touches[0].clientX;
18266         this.endY = e.browserEvent.touches[0].clientY;
18267     },
18268     
18269     onTouchEnd : function(e)
18270     {
18271         if(!this.swiping){
18272             this.onClick(e);
18273             return;
18274         }
18275         
18276         var tabGroup = this.parent();
18277         
18278         if(this.endX > this.startX){ // swiping right
18279             tabGroup.showPanelPrev();
18280             return;
18281         }
18282         
18283         if(this.startX > this.endX){ // swiping left
18284             tabGroup.showPanelNext();
18285             return;
18286         }
18287     }
18288     
18289     
18290 });
18291  
18292
18293  
18294
18295  /*
18296  * - LGPL
18297  *
18298  * DateField
18299  * 
18300  */
18301
18302 /**
18303  * @class Roo.bootstrap.DateField
18304  * @extends Roo.bootstrap.Input
18305  * Bootstrap DateField class
18306  * @cfg {Number} weekStart default 0
18307  * @cfg {String} viewMode default empty, (months|years)
18308  * @cfg {String} minViewMode default empty, (months|years)
18309  * @cfg {Number} startDate default -Infinity
18310  * @cfg {Number} endDate default Infinity
18311  * @cfg {Boolean} todayHighlight default false
18312  * @cfg {Boolean} todayBtn default false
18313  * @cfg {Boolean} calendarWeeks default false
18314  * @cfg {Object} daysOfWeekDisabled default empty
18315  * @cfg {Boolean} singleMode default false (true | false)
18316  * 
18317  * @cfg {Boolean} keyboardNavigation default true
18318  * @cfg {String} language default en
18319  * 
18320  * @constructor
18321  * Create a new DateField
18322  * @param {Object} config The config object
18323  */
18324
18325 Roo.bootstrap.DateField = function(config){
18326     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18327      this.addEvents({
18328             /**
18329              * @event show
18330              * Fires when this field show.
18331              * @param {Roo.bootstrap.DateField} this
18332              * @param {Mixed} date The date value
18333              */
18334             show : true,
18335             /**
18336              * @event show
18337              * Fires when this field hide.
18338              * @param {Roo.bootstrap.DateField} this
18339              * @param {Mixed} date The date value
18340              */
18341             hide : true,
18342             /**
18343              * @event select
18344              * Fires when select a date.
18345              * @param {Roo.bootstrap.DateField} this
18346              * @param {Mixed} date The date value
18347              */
18348             select : true,
18349             /**
18350              * @event beforeselect
18351              * Fires when before select a date.
18352              * @param {Roo.bootstrap.DateField} this
18353              * @param {Mixed} date The date value
18354              */
18355             beforeselect : true
18356         });
18357 };
18358
18359 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18360     
18361     /**
18362      * @cfg {String} format
18363      * The default date format string which can be overriden for localization support.  The format must be
18364      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18365      */
18366     format : "m/d/y",
18367     /**
18368      * @cfg {String} altFormats
18369      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18370      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18371      */
18372     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18373     
18374     weekStart : 0,
18375     
18376     viewMode : '',
18377     
18378     minViewMode : '',
18379     
18380     todayHighlight : false,
18381     
18382     todayBtn: false,
18383     
18384     language: 'en',
18385     
18386     keyboardNavigation: true,
18387     
18388     calendarWeeks: false,
18389     
18390     startDate: -Infinity,
18391     
18392     endDate: Infinity,
18393     
18394     daysOfWeekDisabled: [],
18395     
18396     _events: [],
18397     
18398     singleMode : false,
18399     
18400     UTCDate: function()
18401     {
18402         return new Date(Date.UTC.apply(Date, arguments));
18403     },
18404     
18405     UTCToday: function()
18406     {
18407         var today = new Date();
18408         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18409     },
18410     
18411     getDate: function() {
18412             var d = this.getUTCDate();
18413             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18414     },
18415     
18416     getUTCDate: function() {
18417             return this.date;
18418     },
18419     
18420     setDate: function(d) {
18421             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18422     },
18423     
18424     setUTCDate: function(d) {
18425             this.date = d;
18426             this.setValue(this.formatDate(this.date));
18427     },
18428         
18429     onRender: function(ct, position)
18430     {
18431         
18432         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18433         
18434         this.language = this.language || 'en';
18435         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18436         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18437         
18438         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18439         this.format = this.format || 'm/d/y';
18440         this.isInline = false;
18441         this.isInput = true;
18442         this.component = this.el.select('.add-on', true).first() || false;
18443         this.component = (this.component && this.component.length === 0) ? false : this.component;
18444         this.hasInput = this.component && this.inputEl().length;
18445         
18446         if (typeof(this.minViewMode === 'string')) {
18447             switch (this.minViewMode) {
18448                 case 'months':
18449                     this.minViewMode = 1;
18450                     break;
18451                 case 'years':
18452                     this.minViewMode = 2;
18453                     break;
18454                 default:
18455                     this.minViewMode = 0;
18456                     break;
18457             }
18458         }
18459         
18460         if (typeof(this.viewMode === 'string')) {
18461             switch (this.viewMode) {
18462                 case 'months':
18463                     this.viewMode = 1;
18464                     break;
18465                 case 'years':
18466                     this.viewMode = 2;
18467                     break;
18468                 default:
18469                     this.viewMode = 0;
18470                     break;
18471             }
18472         }
18473                 
18474         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18475         
18476 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18477         
18478         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18479         
18480         this.picker().on('mousedown', this.onMousedown, this);
18481         this.picker().on('click', this.onClick, this);
18482         
18483         this.picker().addClass('datepicker-dropdown');
18484         
18485         this.startViewMode = this.viewMode;
18486         
18487         if(this.singleMode){
18488             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18489                 v.setVisibilityMode(Roo.Element.DISPLAY);
18490                 v.hide();
18491             });
18492             
18493             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18494                 v.setStyle('width', '189px');
18495             });
18496         }
18497         
18498         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18499             if(!this.calendarWeeks){
18500                 v.remove();
18501                 return;
18502             }
18503             
18504             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18505             v.attr('colspan', function(i, val){
18506                 return parseInt(val) + 1;
18507             });
18508         });
18509                         
18510         
18511         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18512         
18513         this.setStartDate(this.startDate);
18514         this.setEndDate(this.endDate);
18515         
18516         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18517         
18518         this.fillDow();
18519         this.fillMonths();
18520         this.update();
18521         this.showMode();
18522         
18523         if(this.isInline) {
18524             this.show();
18525         }
18526     },
18527     
18528     picker : function()
18529     {
18530         return this.pickerEl;
18531 //        return this.el.select('.datepicker', true).first();
18532     },
18533     
18534     fillDow: function()
18535     {
18536         var dowCnt = this.weekStart;
18537         
18538         var dow = {
18539             tag: 'tr',
18540             cn: [
18541                 
18542             ]
18543         };
18544         
18545         if(this.calendarWeeks){
18546             dow.cn.push({
18547                 tag: 'th',
18548                 cls: 'cw',
18549                 html: '&nbsp;'
18550             })
18551         }
18552         
18553         while (dowCnt < this.weekStart + 7) {
18554             dow.cn.push({
18555                 tag: 'th',
18556                 cls: 'dow',
18557                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18558             });
18559         }
18560         
18561         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18562     },
18563     
18564     fillMonths: function()
18565     {    
18566         var i = 0;
18567         var months = this.picker().select('>.datepicker-months td', true).first();
18568         
18569         months.dom.innerHTML = '';
18570         
18571         while (i < 12) {
18572             var month = {
18573                 tag: 'span',
18574                 cls: 'month',
18575                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18576             };
18577             
18578             months.createChild(month);
18579         }
18580         
18581     },
18582     
18583     update: function()
18584     {
18585         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;
18586         
18587         if (this.date < this.startDate) {
18588             this.viewDate = new Date(this.startDate);
18589         } else if (this.date > this.endDate) {
18590             this.viewDate = new Date(this.endDate);
18591         } else {
18592             this.viewDate = new Date(this.date);
18593         }
18594         
18595         this.fill();
18596     },
18597     
18598     fill: function() 
18599     {
18600         var d = new Date(this.viewDate),
18601                 year = d.getUTCFullYear(),
18602                 month = d.getUTCMonth(),
18603                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18604                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18605                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18606                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18607                 currentDate = this.date && this.date.valueOf(),
18608                 today = this.UTCToday();
18609         
18610         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18611         
18612 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18613         
18614 //        this.picker.select('>tfoot th.today').
18615 //                                              .text(dates[this.language].today)
18616 //                                              .toggle(this.todayBtn !== false);
18617     
18618         this.updateNavArrows();
18619         this.fillMonths();
18620                                                 
18621         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18622         
18623         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18624          
18625         prevMonth.setUTCDate(day);
18626         
18627         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18628         
18629         var nextMonth = new Date(prevMonth);
18630         
18631         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18632         
18633         nextMonth = nextMonth.valueOf();
18634         
18635         var fillMonths = false;
18636         
18637         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18638         
18639         while(prevMonth.valueOf() <= nextMonth) {
18640             var clsName = '';
18641             
18642             if (prevMonth.getUTCDay() === this.weekStart) {
18643                 if(fillMonths){
18644                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18645                 }
18646                     
18647                 fillMonths = {
18648                     tag: 'tr',
18649                     cn: []
18650                 };
18651                 
18652                 if(this.calendarWeeks){
18653                     // ISO 8601: First week contains first thursday.
18654                     // ISO also states week starts on Monday, but we can be more abstract here.
18655                     var
18656                     // Start of current week: based on weekstart/current date
18657                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18658                     // Thursday of this week
18659                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18660                     // First Thursday of year, year from thursday
18661                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18662                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18663                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18664                     
18665                     fillMonths.cn.push({
18666                         tag: 'td',
18667                         cls: 'cw',
18668                         html: calWeek
18669                     });
18670                 }
18671             }
18672             
18673             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18674                 clsName += ' old';
18675             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18676                 clsName += ' new';
18677             }
18678             if (this.todayHighlight &&
18679                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18680                 prevMonth.getUTCMonth() == today.getMonth() &&
18681                 prevMonth.getUTCDate() == today.getDate()) {
18682                 clsName += ' today';
18683             }
18684             
18685             if (currentDate && prevMonth.valueOf() === currentDate) {
18686                 clsName += ' active';
18687             }
18688             
18689             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18690                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18691                     clsName += ' disabled';
18692             }
18693             
18694             fillMonths.cn.push({
18695                 tag: 'td',
18696                 cls: 'day ' + clsName,
18697                 html: prevMonth.getDate()
18698             });
18699             
18700             prevMonth.setDate(prevMonth.getDate()+1);
18701         }
18702           
18703         var currentYear = this.date && this.date.getUTCFullYear();
18704         var currentMonth = this.date && this.date.getUTCMonth();
18705         
18706         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18707         
18708         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18709             v.removeClass('active');
18710             
18711             if(currentYear === year && k === currentMonth){
18712                 v.addClass('active');
18713             }
18714             
18715             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18716                 v.addClass('disabled');
18717             }
18718             
18719         });
18720         
18721         
18722         year = parseInt(year/10, 10) * 10;
18723         
18724         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18725         
18726         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18727         
18728         year -= 1;
18729         for (var i = -1; i < 11; i++) {
18730             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18731                 tag: 'span',
18732                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18733                 html: year
18734             });
18735             
18736             year += 1;
18737         }
18738     },
18739     
18740     showMode: function(dir) 
18741     {
18742         if (dir) {
18743             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18744         }
18745         
18746         Roo.each(this.picker().select('>div',true).elements, function(v){
18747             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18748             v.hide();
18749         });
18750         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18751     },
18752     
18753     place: function()
18754     {
18755         if(this.isInline) {
18756             return;
18757         }
18758         
18759         this.picker().removeClass(['bottom', 'top']);
18760         
18761         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18762             /*
18763              * place to the top of element!
18764              *
18765              */
18766             
18767             this.picker().addClass('top');
18768             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18769             
18770             return;
18771         }
18772         
18773         this.picker().addClass('bottom');
18774         
18775         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18776     },
18777     
18778     parseDate : function(value)
18779     {
18780         if(!value || value instanceof Date){
18781             return value;
18782         }
18783         var v = Date.parseDate(value, this.format);
18784         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18785             v = Date.parseDate(value, 'Y-m-d');
18786         }
18787         if(!v && this.altFormats){
18788             if(!this.altFormatsArray){
18789                 this.altFormatsArray = this.altFormats.split("|");
18790             }
18791             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18792                 v = Date.parseDate(value, this.altFormatsArray[i]);
18793             }
18794         }
18795         return v;
18796     },
18797     
18798     formatDate : function(date, fmt)
18799     {   
18800         return (!date || !(date instanceof Date)) ?
18801         date : date.dateFormat(fmt || this.format);
18802     },
18803     
18804     onFocus : function()
18805     {
18806         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18807         this.show();
18808     },
18809     
18810     onBlur : function()
18811     {
18812         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18813         
18814         var d = this.inputEl().getValue();
18815         
18816         this.setValue(d);
18817                 
18818         this.hide();
18819     },
18820     
18821     show : function()
18822     {
18823         this.picker().show();
18824         this.update();
18825         this.place();
18826         
18827         this.fireEvent('show', this, this.date);
18828     },
18829     
18830     hide : function()
18831     {
18832         if(this.isInline) {
18833             return;
18834         }
18835         this.picker().hide();
18836         this.viewMode = this.startViewMode;
18837         this.showMode();
18838         
18839         this.fireEvent('hide', this, this.date);
18840         
18841     },
18842     
18843     onMousedown: function(e)
18844     {
18845         e.stopPropagation();
18846         e.preventDefault();
18847     },
18848     
18849     keyup: function(e)
18850     {
18851         Roo.bootstrap.DateField.superclass.keyup.call(this);
18852         this.update();
18853     },
18854
18855     setValue: function(v)
18856     {
18857         if(this.fireEvent('beforeselect', this, v) !== false){
18858             var d = new Date(this.parseDate(v) ).clearTime();
18859         
18860             if(isNaN(d.getTime())){
18861                 this.date = this.viewDate = '';
18862                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18863                 return;
18864             }
18865
18866             v = this.formatDate(d);
18867
18868             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18869
18870             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18871
18872             this.update();
18873
18874             this.fireEvent('select', this, this.date);
18875         }
18876     },
18877     
18878     getValue: function()
18879     {
18880         return this.formatDate(this.date);
18881     },
18882     
18883     fireKey: function(e)
18884     {
18885         if (!this.picker().isVisible()){
18886             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18887                 this.show();
18888             }
18889             return;
18890         }
18891         
18892         var dateChanged = false,
18893         dir, day, month,
18894         newDate, newViewDate;
18895         
18896         switch(e.keyCode){
18897             case 27: // escape
18898                 this.hide();
18899                 e.preventDefault();
18900                 break;
18901             case 37: // left
18902             case 39: // right
18903                 if (!this.keyboardNavigation) {
18904                     break;
18905                 }
18906                 dir = e.keyCode == 37 ? -1 : 1;
18907                 
18908                 if (e.ctrlKey){
18909                     newDate = this.moveYear(this.date, dir);
18910                     newViewDate = this.moveYear(this.viewDate, dir);
18911                 } else if (e.shiftKey){
18912                     newDate = this.moveMonth(this.date, dir);
18913                     newViewDate = this.moveMonth(this.viewDate, dir);
18914                 } else {
18915                     newDate = new Date(this.date);
18916                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18917                     newViewDate = new Date(this.viewDate);
18918                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18919                 }
18920                 if (this.dateWithinRange(newDate)){
18921                     this.date = newDate;
18922                     this.viewDate = newViewDate;
18923                     this.setValue(this.formatDate(this.date));
18924 //                    this.update();
18925                     e.preventDefault();
18926                     dateChanged = true;
18927                 }
18928                 break;
18929             case 38: // up
18930             case 40: // down
18931                 if (!this.keyboardNavigation) {
18932                     break;
18933                 }
18934                 dir = e.keyCode == 38 ? -1 : 1;
18935                 if (e.ctrlKey){
18936                     newDate = this.moveYear(this.date, dir);
18937                     newViewDate = this.moveYear(this.viewDate, dir);
18938                 } else if (e.shiftKey){
18939                     newDate = this.moveMonth(this.date, dir);
18940                     newViewDate = this.moveMonth(this.viewDate, dir);
18941                 } else {
18942                     newDate = new Date(this.date);
18943                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18944                     newViewDate = new Date(this.viewDate);
18945                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18946                 }
18947                 if (this.dateWithinRange(newDate)){
18948                     this.date = newDate;
18949                     this.viewDate = newViewDate;
18950                     this.setValue(this.formatDate(this.date));
18951 //                    this.update();
18952                     e.preventDefault();
18953                     dateChanged = true;
18954                 }
18955                 break;
18956             case 13: // enter
18957                 this.setValue(this.formatDate(this.date));
18958                 this.hide();
18959                 e.preventDefault();
18960                 break;
18961             case 9: // tab
18962                 this.setValue(this.formatDate(this.date));
18963                 this.hide();
18964                 break;
18965             case 16: // shift
18966             case 17: // ctrl
18967             case 18: // alt
18968                 break;
18969             default :
18970                 this.hide();
18971                 
18972         }
18973     },
18974     
18975     
18976     onClick: function(e) 
18977     {
18978         e.stopPropagation();
18979         e.preventDefault();
18980         
18981         var target = e.getTarget();
18982         
18983         if(target.nodeName.toLowerCase() === 'i'){
18984             target = Roo.get(target).dom.parentNode;
18985         }
18986         
18987         var nodeName = target.nodeName;
18988         var className = target.className;
18989         var html = target.innerHTML;
18990         //Roo.log(nodeName);
18991         
18992         switch(nodeName.toLowerCase()) {
18993             case 'th':
18994                 switch(className) {
18995                     case 'switch':
18996                         this.showMode(1);
18997                         break;
18998                     case 'prev':
18999                     case 'next':
19000                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19001                         switch(this.viewMode){
19002                                 case 0:
19003                                         this.viewDate = this.moveMonth(this.viewDate, dir);
19004                                         break;
19005                                 case 1:
19006                                 case 2:
19007                                         this.viewDate = this.moveYear(this.viewDate, dir);
19008                                         break;
19009                         }
19010                         this.fill();
19011                         break;
19012                     case 'today':
19013                         var date = new Date();
19014                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19015 //                        this.fill()
19016                         this.setValue(this.formatDate(this.date));
19017                         
19018                         this.hide();
19019                         break;
19020                 }
19021                 break;
19022             case 'span':
19023                 if (className.indexOf('disabled') < 0) {
19024                     this.viewDate.setUTCDate(1);
19025                     if (className.indexOf('month') > -1) {
19026                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19027                     } else {
19028                         var year = parseInt(html, 10) || 0;
19029                         this.viewDate.setUTCFullYear(year);
19030                         
19031                     }
19032                     
19033                     if(this.singleMode){
19034                         this.setValue(this.formatDate(this.viewDate));
19035                         this.hide();
19036                         return;
19037                     }
19038                     
19039                     this.showMode(-1);
19040                     this.fill();
19041                 }
19042                 break;
19043                 
19044             case 'td':
19045                 //Roo.log(className);
19046                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19047                     var day = parseInt(html, 10) || 1;
19048                     var year = this.viewDate.getUTCFullYear(),
19049                         month = this.viewDate.getUTCMonth();
19050
19051                     if (className.indexOf('old') > -1) {
19052                         if(month === 0 ){
19053                             month = 11;
19054                             year -= 1;
19055                         }else{
19056                             month -= 1;
19057                         }
19058                     } else if (className.indexOf('new') > -1) {
19059                         if (month == 11) {
19060                             month = 0;
19061                             year += 1;
19062                         } else {
19063                             month += 1;
19064                         }
19065                     }
19066                     //Roo.log([year,month,day]);
19067                     this.date = this.UTCDate(year, month, day,0,0,0,0);
19068                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19069 //                    this.fill();
19070                     //Roo.log(this.formatDate(this.date));
19071                     this.setValue(this.formatDate(this.date));
19072                     this.hide();
19073                 }
19074                 break;
19075         }
19076     },
19077     
19078     setStartDate: function(startDate)
19079     {
19080         this.startDate = startDate || -Infinity;
19081         if (this.startDate !== -Infinity) {
19082             this.startDate = this.parseDate(this.startDate);
19083         }
19084         this.update();
19085         this.updateNavArrows();
19086     },
19087
19088     setEndDate: function(endDate)
19089     {
19090         this.endDate = endDate || Infinity;
19091         if (this.endDate !== Infinity) {
19092             this.endDate = this.parseDate(this.endDate);
19093         }
19094         this.update();
19095         this.updateNavArrows();
19096     },
19097     
19098     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19099     {
19100         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19101         if (typeof(this.daysOfWeekDisabled) !== 'object') {
19102             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19103         }
19104         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19105             return parseInt(d, 10);
19106         });
19107         this.update();
19108         this.updateNavArrows();
19109     },
19110     
19111     updateNavArrows: function() 
19112     {
19113         if(this.singleMode){
19114             return;
19115         }
19116         
19117         var d = new Date(this.viewDate),
19118         year = d.getUTCFullYear(),
19119         month = d.getUTCMonth();
19120         
19121         Roo.each(this.picker().select('.prev', true).elements, function(v){
19122             v.show();
19123             switch (this.viewMode) {
19124                 case 0:
19125
19126                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19127                         v.hide();
19128                     }
19129                     break;
19130                 case 1:
19131                 case 2:
19132                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19133                         v.hide();
19134                     }
19135                     break;
19136             }
19137         });
19138         
19139         Roo.each(this.picker().select('.next', true).elements, function(v){
19140             v.show();
19141             switch (this.viewMode) {
19142                 case 0:
19143
19144                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19145                         v.hide();
19146                     }
19147                     break;
19148                 case 1:
19149                 case 2:
19150                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19151                         v.hide();
19152                     }
19153                     break;
19154             }
19155         })
19156     },
19157     
19158     moveMonth: function(date, dir)
19159     {
19160         if (!dir) {
19161             return date;
19162         }
19163         var new_date = new Date(date.valueOf()),
19164         day = new_date.getUTCDate(),
19165         month = new_date.getUTCMonth(),
19166         mag = Math.abs(dir),
19167         new_month, test;
19168         dir = dir > 0 ? 1 : -1;
19169         if (mag == 1){
19170             test = dir == -1
19171             // If going back one month, make sure month is not current month
19172             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19173             ? function(){
19174                 return new_date.getUTCMonth() == month;
19175             }
19176             // If going forward one month, make sure month is as expected
19177             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19178             : function(){
19179                 return new_date.getUTCMonth() != new_month;
19180             };
19181             new_month = month + dir;
19182             new_date.setUTCMonth(new_month);
19183             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19184             if (new_month < 0 || new_month > 11) {
19185                 new_month = (new_month + 12) % 12;
19186             }
19187         } else {
19188             // For magnitudes >1, move one month at a time...
19189             for (var i=0; i<mag; i++) {
19190                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19191                 new_date = this.moveMonth(new_date, dir);
19192             }
19193             // ...then reset the day, keeping it in the new month
19194             new_month = new_date.getUTCMonth();
19195             new_date.setUTCDate(day);
19196             test = function(){
19197                 return new_month != new_date.getUTCMonth();
19198             };
19199         }
19200         // Common date-resetting loop -- if date is beyond end of month, make it
19201         // end of month
19202         while (test()){
19203             new_date.setUTCDate(--day);
19204             new_date.setUTCMonth(new_month);
19205         }
19206         return new_date;
19207     },
19208
19209     moveYear: function(date, dir)
19210     {
19211         return this.moveMonth(date, dir*12);
19212     },
19213
19214     dateWithinRange: function(date)
19215     {
19216         return date >= this.startDate && date <= this.endDate;
19217     },
19218
19219     
19220     remove: function() 
19221     {
19222         this.picker().remove();
19223     },
19224     
19225     validateValue : function(value)
19226     {
19227         if(this.getVisibilityEl().hasClass('hidden')){
19228             return true;
19229         }
19230         
19231         if(value.length < 1)  {
19232             if(this.allowBlank){
19233                 return true;
19234             }
19235             return false;
19236         }
19237         
19238         if(value.length < this.minLength){
19239             return false;
19240         }
19241         if(value.length > this.maxLength){
19242             return false;
19243         }
19244         if(this.vtype){
19245             var vt = Roo.form.VTypes;
19246             if(!vt[this.vtype](value, this)){
19247                 return false;
19248             }
19249         }
19250         if(typeof this.validator == "function"){
19251             var msg = this.validator(value);
19252             if(msg !== true){
19253                 return false;
19254             }
19255         }
19256         
19257         if(this.regex && !this.regex.test(value)){
19258             return false;
19259         }
19260         
19261         if(typeof(this.parseDate(value)) == 'undefined'){
19262             return false;
19263         }
19264         
19265         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19266             return false;
19267         }      
19268         
19269         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19270             return false;
19271         } 
19272         
19273         
19274         return true;
19275     },
19276     
19277     reset : function()
19278     {
19279         this.date = this.viewDate = '';
19280         
19281         Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19282     },
19283     
19284     setVisible : function(visible)
19285     {
19286         if(!this.getEl()){
19287             return;
19288         }
19289         
19290         this.getEl().removeClass('hidden');
19291         
19292         if(visible){
19293             return;
19294         }
19295         
19296         this.getEl().addClass('hidden');
19297     }
19298    
19299 });
19300
19301 Roo.apply(Roo.bootstrap.DateField,  {
19302     
19303     head : {
19304         tag: 'thead',
19305         cn: [
19306         {
19307             tag: 'tr',
19308             cn: [
19309             {
19310                 tag: 'th',
19311                 cls: 'prev',
19312                 html: '<i class="fa fa-arrow-left"/>'
19313             },
19314             {
19315                 tag: 'th',
19316                 cls: 'switch',
19317                 colspan: '5'
19318             },
19319             {
19320                 tag: 'th',
19321                 cls: 'next',
19322                 html: '<i class="fa fa-arrow-right"/>'
19323             }
19324
19325             ]
19326         }
19327         ]
19328     },
19329     
19330     content : {
19331         tag: 'tbody',
19332         cn: [
19333         {
19334             tag: 'tr',
19335             cn: [
19336             {
19337                 tag: 'td',
19338                 colspan: '7'
19339             }
19340             ]
19341         }
19342         ]
19343     },
19344     
19345     footer : {
19346         tag: 'tfoot',
19347         cn: [
19348         {
19349             tag: 'tr',
19350             cn: [
19351             {
19352                 tag: 'th',
19353                 colspan: '7',
19354                 cls: 'today'
19355             }
19356                     
19357             ]
19358         }
19359         ]
19360     },
19361     
19362     dates:{
19363         en: {
19364             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19365             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19366             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19367             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19368             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19369             today: "Today"
19370         }
19371     },
19372     
19373     modes: [
19374     {
19375         clsName: 'days',
19376         navFnc: 'Month',
19377         navStep: 1
19378     },
19379     {
19380         clsName: 'months',
19381         navFnc: 'FullYear',
19382         navStep: 1
19383     },
19384     {
19385         clsName: 'years',
19386         navFnc: 'FullYear',
19387         navStep: 10
19388     }]
19389 });
19390
19391 Roo.apply(Roo.bootstrap.DateField,  {
19392   
19393     template : {
19394         tag: 'div',
19395         cls: 'datepicker dropdown-menu roo-dynamic',
19396         cn: [
19397         {
19398             tag: 'div',
19399             cls: 'datepicker-days',
19400             cn: [
19401             {
19402                 tag: 'table',
19403                 cls: 'table-condensed',
19404                 cn:[
19405                 Roo.bootstrap.DateField.head,
19406                 {
19407                     tag: 'tbody'
19408                 },
19409                 Roo.bootstrap.DateField.footer
19410                 ]
19411             }
19412             ]
19413         },
19414         {
19415             tag: 'div',
19416             cls: 'datepicker-months',
19417             cn: [
19418             {
19419                 tag: 'table',
19420                 cls: 'table-condensed',
19421                 cn:[
19422                 Roo.bootstrap.DateField.head,
19423                 Roo.bootstrap.DateField.content,
19424                 Roo.bootstrap.DateField.footer
19425                 ]
19426             }
19427             ]
19428         },
19429         {
19430             tag: 'div',
19431             cls: 'datepicker-years',
19432             cn: [
19433             {
19434                 tag: 'table',
19435                 cls: 'table-condensed',
19436                 cn:[
19437                 Roo.bootstrap.DateField.head,
19438                 Roo.bootstrap.DateField.content,
19439                 Roo.bootstrap.DateField.footer
19440                 ]
19441             }
19442             ]
19443         }
19444         ]
19445     }
19446 });
19447
19448  
19449
19450  /*
19451  * - LGPL
19452  *
19453  * TimeField
19454  * 
19455  */
19456
19457 /**
19458  * @class Roo.bootstrap.TimeField
19459  * @extends Roo.bootstrap.Input
19460  * Bootstrap DateField class
19461  * 
19462  * 
19463  * @constructor
19464  * Create a new TimeField
19465  * @param {Object} config The config object
19466  */
19467
19468 Roo.bootstrap.TimeField = function(config){
19469     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19470     this.addEvents({
19471             /**
19472              * @event show
19473              * Fires when this field show.
19474              * @param {Roo.bootstrap.DateField} thisthis
19475              * @param {Mixed} date The date value
19476              */
19477             show : true,
19478             /**
19479              * @event show
19480              * Fires when this field hide.
19481              * @param {Roo.bootstrap.DateField} this
19482              * @param {Mixed} date The date value
19483              */
19484             hide : true,
19485             /**
19486              * @event select
19487              * Fires when select a date.
19488              * @param {Roo.bootstrap.DateField} this
19489              * @param {Mixed} date The date value
19490              */
19491             select : true
19492         });
19493 };
19494
19495 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19496     
19497     /**
19498      * @cfg {String} format
19499      * The default time format string which can be overriden for localization support.  The format must be
19500      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19501      */
19502     format : "H:i",
19503        
19504     onRender: function(ct, position)
19505     {
19506         
19507         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19508                 
19509         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19510         
19511         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19512         
19513         this.pop = this.picker().select('>.datepicker-time',true).first();
19514         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19515         
19516         this.picker().on('mousedown', this.onMousedown, this);
19517         this.picker().on('click', this.onClick, this);
19518         
19519         this.picker().addClass('datepicker-dropdown');
19520     
19521         this.fillTime();
19522         this.update();
19523             
19524         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19525         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19526         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19527         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19528         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19529         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19530
19531     },
19532     
19533     fireKey: function(e){
19534         if (!this.picker().isVisible()){
19535             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19536                 this.show();
19537             }
19538             return;
19539         }
19540
19541         e.preventDefault();
19542         
19543         switch(e.keyCode){
19544             case 27: // escape
19545                 this.hide();
19546                 break;
19547             case 37: // left
19548             case 39: // right
19549                 this.onTogglePeriod();
19550                 break;
19551             case 38: // up
19552                 this.onIncrementMinutes();
19553                 break;
19554             case 40: // down
19555                 this.onDecrementMinutes();
19556                 break;
19557             case 13: // enter
19558             case 9: // tab
19559                 this.setTime();
19560                 break;
19561         }
19562     },
19563     
19564     onClick: function(e) {
19565         e.stopPropagation();
19566         e.preventDefault();
19567     },
19568     
19569     picker : function()
19570     {
19571         return this.el.select('.datepicker', true).first();
19572     },
19573     
19574     fillTime: function()
19575     {    
19576         var time = this.pop.select('tbody', true).first();
19577         
19578         time.dom.innerHTML = '';
19579         
19580         time.createChild({
19581             tag: 'tr',
19582             cn: [
19583                 {
19584                     tag: 'td',
19585                     cn: [
19586                         {
19587                             tag: 'a',
19588                             href: '#',
19589                             cls: 'btn',
19590                             cn: [
19591                                 {
19592                                     tag: 'span',
19593                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19594                                 }
19595                             ]
19596                         } 
19597                     ]
19598                 },
19599                 {
19600                     tag: 'td',
19601                     cls: 'separator'
19602                 },
19603                 {
19604                     tag: 'td',
19605                     cn: [
19606                         {
19607                             tag: 'a',
19608                             href: '#',
19609                             cls: 'btn',
19610                             cn: [
19611                                 {
19612                                     tag: 'span',
19613                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19614                                 }
19615                             ]
19616                         }
19617                     ]
19618                 },
19619                 {
19620                     tag: 'td',
19621                     cls: 'separator'
19622                 }
19623             ]
19624         });
19625         
19626         time.createChild({
19627             tag: 'tr',
19628             cn: [
19629                 {
19630                     tag: 'td',
19631                     cn: [
19632                         {
19633                             tag: 'span',
19634                             cls: 'timepicker-hour',
19635                             html: '00'
19636                         }  
19637                     ]
19638                 },
19639                 {
19640                     tag: 'td',
19641                     cls: 'separator',
19642                     html: ':'
19643                 },
19644                 {
19645                     tag: 'td',
19646                     cn: [
19647                         {
19648                             tag: 'span',
19649                             cls: 'timepicker-minute',
19650                             html: '00'
19651                         }  
19652                     ]
19653                 },
19654                 {
19655                     tag: 'td',
19656                     cls: 'separator'
19657                 },
19658                 {
19659                     tag: 'td',
19660                     cn: [
19661                         {
19662                             tag: 'button',
19663                             type: 'button',
19664                             cls: 'btn btn-primary period',
19665                             html: 'AM'
19666                             
19667                         }
19668                     ]
19669                 }
19670             ]
19671         });
19672         
19673         time.createChild({
19674             tag: 'tr',
19675             cn: [
19676                 {
19677                     tag: 'td',
19678                     cn: [
19679                         {
19680                             tag: 'a',
19681                             href: '#',
19682                             cls: 'btn',
19683                             cn: [
19684                                 {
19685                                     tag: 'span',
19686                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19687                                 }
19688                             ]
19689                         }
19690                     ]
19691                 },
19692                 {
19693                     tag: 'td',
19694                     cls: 'separator'
19695                 },
19696                 {
19697                     tag: 'td',
19698                     cn: [
19699                         {
19700                             tag: 'a',
19701                             href: '#',
19702                             cls: 'btn',
19703                             cn: [
19704                                 {
19705                                     tag: 'span',
19706                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19707                                 }
19708                             ]
19709                         }
19710                     ]
19711                 },
19712                 {
19713                     tag: 'td',
19714                     cls: 'separator'
19715                 }
19716             ]
19717         });
19718         
19719     },
19720     
19721     update: function()
19722     {
19723         
19724         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19725         
19726         this.fill();
19727     },
19728     
19729     fill: function() 
19730     {
19731         var hours = this.time.getHours();
19732         var minutes = this.time.getMinutes();
19733         var period = 'AM';
19734         
19735         if(hours > 11){
19736             period = 'PM';
19737         }
19738         
19739         if(hours == 0){
19740             hours = 12;
19741         }
19742         
19743         
19744         if(hours > 12){
19745             hours = hours - 12;
19746         }
19747         
19748         if(hours < 10){
19749             hours = '0' + hours;
19750         }
19751         
19752         if(minutes < 10){
19753             minutes = '0' + minutes;
19754         }
19755         
19756         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19757         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19758         this.pop.select('button', true).first().dom.innerHTML = period;
19759         
19760     },
19761     
19762     place: function()
19763     {   
19764         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19765         
19766         var cls = ['bottom'];
19767         
19768         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19769             cls.pop();
19770             cls.push('top');
19771         }
19772         
19773         cls.push('right');
19774         
19775         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19776             cls.pop();
19777             cls.push('left');
19778         }
19779         
19780         this.picker().addClass(cls.join('-'));
19781         
19782         var _this = this;
19783         
19784         Roo.each(cls, function(c){
19785             if(c == 'bottom'){
19786                 _this.picker().setTop(_this.inputEl().getHeight());
19787                 return;
19788             }
19789             if(c == 'top'){
19790                 _this.picker().setTop(0 - _this.picker().getHeight());
19791                 return;
19792             }
19793             
19794             if(c == 'left'){
19795                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19796                 return;
19797             }
19798             if(c == 'right'){
19799                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19800                 return;
19801             }
19802         });
19803         
19804     },
19805   
19806     onFocus : function()
19807     {
19808         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19809         this.show();
19810     },
19811     
19812     onBlur : function()
19813     {
19814         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19815         this.hide();
19816     },
19817     
19818     show : function()
19819     {
19820         this.picker().show();
19821         this.pop.show();
19822         this.update();
19823         this.place();
19824         
19825         this.fireEvent('show', this, this.date);
19826     },
19827     
19828     hide : function()
19829     {
19830         this.picker().hide();
19831         this.pop.hide();
19832         
19833         this.fireEvent('hide', this, this.date);
19834     },
19835     
19836     setTime : function()
19837     {
19838         this.hide();
19839         this.setValue(this.time.format(this.format));
19840         
19841         this.fireEvent('select', this, this.date);
19842         
19843         
19844     },
19845     
19846     onMousedown: function(e){
19847         e.stopPropagation();
19848         e.preventDefault();
19849     },
19850     
19851     onIncrementHours: function()
19852     {
19853         Roo.log('onIncrementHours');
19854         this.time = this.time.add(Date.HOUR, 1);
19855         this.update();
19856         
19857     },
19858     
19859     onDecrementHours: function()
19860     {
19861         Roo.log('onDecrementHours');
19862         this.time = this.time.add(Date.HOUR, -1);
19863         this.update();
19864     },
19865     
19866     onIncrementMinutes: function()
19867     {
19868         Roo.log('onIncrementMinutes');
19869         this.time = this.time.add(Date.MINUTE, 1);
19870         this.update();
19871     },
19872     
19873     onDecrementMinutes: function()
19874     {
19875         Roo.log('onDecrementMinutes');
19876         this.time = this.time.add(Date.MINUTE, -1);
19877         this.update();
19878     },
19879     
19880     onTogglePeriod: function()
19881     {
19882         Roo.log('onTogglePeriod');
19883         this.time = this.time.add(Date.HOUR, 12);
19884         this.update();
19885     }
19886     
19887    
19888 });
19889
19890 Roo.apply(Roo.bootstrap.TimeField,  {
19891     
19892     content : {
19893         tag: 'tbody',
19894         cn: [
19895             {
19896                 tag: 'tr',
19897                 cn: [
19898                 {
19899                     tag: 'td',
19900                     colspan: '7'
19901                 }
19902                 ]
19903             }
19904         ]
19905     },
19906     
19907     footer : {
19908         tag: 'tfoot',
19909         cn: [
19910             {
19911                 tag: 'tr',
19912                 cn: [
19913                 {
19914                     tag: 'th',
19915                     colspan: '7',
19916                     cls: '',
19917                     cn: [
19918                         {
19919                             tag: 'button',
19920                             cls: 'btn btn-info ok',
19921                             html: 'OK'
19922                         }
19923                     ]
19924                 }
19925
19926                 ]
19927             }
19928         ]
19929     }
19930 });
19931
19932 Roo.apply(Roo.bootstrap.TimeField,  {
19933   
19934     template : {
19935         tag: 'div',
19936         cls: 'datepicker dropdown-menu',
19937         cn: [
19938             {
19939                 tag: 'div',
19940                 cls: 'datepicker-time',
19941                 cn: [
19942                 {
19943                     tag: 'table',
19944                     cls: 'table-condensed',
19945                     cn:[
19946                     Roo.bootstrap.TimeField.content,
19947                     Roo.bootstrap.TimeField.footer
19948                     ]
19949                 }
19950                 ]
19951             }
19952         ]
19953     }
19954 });
19955
19956  
19957
19958  /*
19959  * - LGPL
19960  *
19961  * MonthField
19962  * 
19963  */
19964
19965 /**
19966  * @class Roo.bootstrap.MonthField
19967  * @extends Roo.bootstrap.Input
19968  * Bootstrap MonthField class
19969  * 
19970  * @cfg {String} language default en
19971  * 
19972  * @constructor
19973  * Create a new MonthField
19974  * @param {Object} config The config object
19975  */
19976
19977 Roo.bootstrap.MonthField = function(config){
19978     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19979     
19980     this.addEvents({
19981         /**
19982          * @event show
19983          * Fires when this field show.
19984          * @param {Roo.bootstrap.MonthField} this
19985          * @param {Mixed} date The date value
19986          */
19987         show : true,
19988         /**
19989          * @event show
19990          * Fires when this field hide.
19991          * @param {Roo.bootstrap.MonthField} this
19992          * @param {Mixed} date The date value
19993          */
19994         hide : true,
19995         /**
19996          * @event select
19997          * Fires when select a date.
19998          * @param {Roo.bootstrap.MonthField} this
19999          * @param {String} oldvalue The old value
20000          * @param {String} newvalue The new value
20001          */
20002         select : true
20003     });
20004 };
20005
20006 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
20007     
20008     onRender: function(ct, position)
20009     {
20010         
20011         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20012         
20013         this.language = this.language || 'en';
20014         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20015         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20016         
20017         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20018         this.isInline = false;
20019         this.isInput = true;
20020         this.component = this.el.select('.add-on', true).first() || false;
20021         this.component = (this.component && this.component.length === 0) ? false : this.component;
20022         this.hasInput = this.component && this.inputEL().length;
20023         
20024         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20025         
20026         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20027         
20028         this.picker().on('mousedown', this.onMousedown, this);
20029         this.picker().on('click', this.onClick, this);
20030         
20031         this.picker().addClass('datepicker-dropdown');
20032         
20033         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20034             v.setStyle('width', '189px');
20035         });
20036         
20037         this.fillMonths();
20038         
20039         this.update();
20040         
20041         if(this.isInline) {
20042             this.show();
20043         }
20044         
20045     },
20046     
20047     setValue: function(v, suppressEvent)
20048     {   
20049         var o = this.getValue();
20050         
20051         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20052         
20053         this.update();
20054
20055         if(suppressEvent !== true){
20056             this.fireEvent('select', this, o, v);
20057         }
20058         
20059     },
20060     
20061     getValue: function()
20062     {
20063         return this.value;
20064     },
20065     
20066     onClick: function(e) 
20067     {
20068         e.stopPropagation();
20069         e.preventDefault();
20070         
20071         var target = e.getTarget();
20072         
20073         if(target.nodeName.toLowerCase() === 'i'){
20074             target = Roo.get(target).dom.parentNode;
20075         }
20076         
20077         var nodeName = target.nodeName;
20078         var className = target.className;
20079         var html = target.innerHTML;
20080         
20081         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20082             return;
20083         }
20084         
20085         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20086         
20087         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20088         
20089         this.hide();
20090                         
20091     },
20092     
20093     picker : function()
20094     {
20095         return this.pickerEl;
20096     },
20097     
20098     fillMonths: function()
20099     {    
20100         var i = 0;
20101         var months = this.picker().select('>.datepicker-months td', true).first();
20102         
20103         months.dom.innerHTML = '';
20104         
20105         while (i < 12) {
20106             var month = {
20107                 tag: 'span',
20108                 cls: 'month',
20109                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20110             };
20111             
20112             months.createChild(month);
20113         }
20114         
20115     },
20116     
20117     update: function()
20118     {
20119         var _this = this;
20120         
20121         if(typeof(this.vIndex) == 'undefined' && this.value.length){
20122             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20123         }
20124         
20125         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20126             e.removeClass('active');
20127             
20128             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20129                 e.addClass('active');
20130             }
20131         })
20132     },
20133     
20134     place: function()
20135     {
20136         if(this.isInline) {
20137             return;
20138         }
20139         
20140         this.picker().removeClass(['bottom', 'top']);
20141         
20142         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20143             /*
20144              * place to the top of element!
20145              *
20146              */
20147             
20148             this.picker().addClass('top');
20149             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20150             
20151             return;
20152         }
20153         
20154         this.picker().addClass('bottom');
20155         
20156         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20157     },
20158     
20159     onFocus : function()
20160     {
20161         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20162         this.show();
20163     },
20164     
20165     onBlur : function()
20166     {
20167         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20168         
20169         var d = this.inputEl().getValue();
20170         
20171         this.setValue(d);
20172                 
20173         this.hide();
20174     },
20175     
20176     show : function()
20177     {
20178         this.picker().show();
20179         this.picker().select('>.datepicker-months', true).first().show();
20180         this.update();
20181         this.place();
20182         
20183         this.fireEvent('show', this, this.date);
20184     },
20185     
20186     hide : function()
20187     {
20188         if(this.isInline) {
20189             return;
20190         }
20191         this.picker().hide();
20192         this.fireEvent('hide', this, this.date);
20193         
20194     },
20195     
20196     onMousedown: function(e)
20197     {
20198         e.stopPropagation();
20199         e.preventDefault();
20200     },
20201     
20202     keyup: function(e)
20203     {
20204         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20205         this.update();
20206     },
20207
20208     fireKey: function(e)
20209     {
20210         if (!this.picker().isVisible()){
20211             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20212                 this.show();
20213             }
20214             return;
20215         }
20216         
20217         var dir;
20218         
20219         switch(e.keyCode){
20220             case 27: // escape
20221                 this.hide();
20222                 e.preventDefault();
20223                 break;
20224             case 37: // left
20225             case 39: // right
20226                 dir = e.keyCode == 37 ? -1 : 1;
20227                 
20228                 this.vIndex = this.vIndex + dir;
20229                 
20230                 if(this.vIndex < 0){
20231                     this.vIndex = 0;
20232                 }
20233                 
20234                 if(this.vIndex > 11){
20235                     this.vIndex = 11;
20236                 }
20237                 
20238                 if(isNaN(this.vIndex)){
20239                     this.vIndex = 0;
20240                 }
20241                 
20242                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20243                 
20244                 break;
20245             case 38: // up
20246             case 40: // down
20247                 
20248                 dir = e.keyCode == 38 ? -1 : 1;
20249                 
20250                 this.vIndex = this.vIndex + dir * 4;
20251                 
20252                 if(this.vIndex < 0){
20253                     this.vIndex = 0;
20254                 }
20255                 
20256                 if(this.vIndex > 11){
20257                     this.vIndex = 11;
20258                 }
20259                 
20260                 if(isNaN(this.vIndex)){
20261                     this.vIndex = 0;
20262                 }
20263                 
20264                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20265                 break;
20266                 
20267             case 13: // enter
20268                 
20269                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20270                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20271                 }
20272                 
20273                 this.hide();
20274                 e.preventDefault();
20275                 break;
20276             case 9: // tab
20277                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20278                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20279                 }
20280                 this.hide();
20281                 break;
20282             case 16: // shift
20283             case 17: // ctrl
20284             case 18: // alt
20285                 break;
20286             default :
20287                 this.hide();
20288                 
20289         }
20290     },
20291     
20292     remove: function() 
20293     {
20294         this.picker().remove();
20295     }
20296    
20297 });
20298
20299 Roo.apply(Roo.bootstrap.MonthField,  {
20300     
20301     content : {
20302         tag: 'tbody',
20303         cn: [
20304         {
20305             tag: 'tr',
20306             cn: [
20307             {
20308                 tag: 'td',
20309                 colspan: '7'
20310             }
20311             ]
20312         }
20313         ]
20314     },
20315     
20316     dates:{
20317         en: {
20318             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20319             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20320         }
20321     }
20322 });
20323
20324 Roo.apply(Roo.bootstrap.MonthField,  {
20325   
20326     template : {
20327         tag: 'div',
20328         cls: 'datepicker dropdown-menu roo-dynamic',
20329         cn: [
20330             {
20331                 tag: 'div',
20332                 cls: 'datepicker-months',
20333                 cn: [
20334                 {
20335                     tag: 'table',
20336                     cls: 'table-condensed',
20337                     cn:[
20338                         Roo.bootstrap.DateField.content
20339                     ]
20340                 }
20341                 ]
20342             }
20343         ]
20344     }
20345 });
20346
20347  
20348
20349  
20350  /*
20351  * - LGPL
20352  *
20353  * CheckBox
20354  * 
20355  */
20356
20357 /**
20358  * @class Roo.bootstrap.CheckBox
20359  * @extends Roo.bootstrap.Input
20360  * Bootstrap CheckBox class
20361  * 
20362  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20363  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20364  * @cfg {String} boxLabel The text that appears beside the checkbox
20365  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20366  * @cfg {Boolean} checked initnal the element
20367  * @cfg {Boolean} inline inline the element (default false)
20368  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20369  * @cfg {String} tooltip label tooltip
20370  * 
20371  * @constructor
20372  * Create a new CheckBox
20373  * @param {Object} config The config object
20374  */
20375
20376 Roo.bootstrap.CheckBox = function(config){
20377     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20378    
20379     this.addEvents({
20380         /**
20381         * @event check
20382         * Fires when the element is checked or unchecked.
20383         * @param {Roo.bootstrap.CheckBox} this This input
20384         * @param {Boolean} checked The new checked value
20385         */
20386        check : true,
20387        /**
20388         * @event click
20389         * Fires when the element is click.
20390         * @param {Roo.bootstrap.CheckBox} this This input
20391         */
20392        click : true
20393     });
20394     
20395 };
20396
20397 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20398   
20399     inputType: 'checkbox',
20400     inputValue: 1,
20401     valueOff: 0,
20402     boxLabel: false,
20403     checked: false,
20404     weight : false,
20405     inline: false,
20406     tooltip : '',
20407     
20408     getAutoCreate : function()
20409     {
20410         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20411         
20412         var id = Roo.id();
20413         
20414         var cfg = {};
20415         
20416         cfg.cls = 'form-group ' + this.inputType; //input-group
20417         
20418         if(this.inline){
20419             cfg.cls += ' ' + this.inputType + '-inline';
20420         }
20421         
20422         var input =  {
20423             tag: 'input',
20424             id : id,
20425             type : this.inputType,
20426             value : this.inputValue,
20427             cls : 'roo-' + this.inputType, //'form-box',
20428             placeholder : this.placeholder || ''
20429             
20430         };
20431         
20432         if(this.inputType != 'radio'){
20433             var hidden =  {
20434                 tag: 'input',
20435                 type : 'hidden',
20436                 cls : 'roo-hidden-value',
20437                 value : this.checked ? this.inputValue : this.valueOff
20438             };
20439         }
20440         
20441             
20442         if (this.weight) { // Validity check?
20443             cfg.cls += " " + this.inputType + "-" + this.weight;
20444         }
20445         
20446         if (this.disabled) {
20447             input.disabled=true;
20448         }
20449         
20450         if(this.checked){
20451             input.checked = this.checked;
20452         }
20453         
20454         if (this.name) {
20455             
20456             input.name = this.name;
20457             
20458             if(this.inputType != 'radio'){
20459                 hidden.name = this.name;
20460                 input.name = '_hidden_' + this.name;
20461             }
20462         }
20463         
20464         if (this.size) {
20465             input.cls += ' input-' + this.size;
20466         }
20467         
20468         var settings=this;
20469         
20470         ['xs','sm','md','lg'].map(function(size){
20471             if (settings[size]) {
20472                 cfg.cls += ' col-' + size + '-' + settings[size];
20473             }
20474         });
20475         
20476         var inputblock = input;
20477          
20478         if (this.before || this.after) {
20479             
20480             inputblock = {
20481                 cls : 'input-group',
20482                 cn :  [] 
20483             };
20484             
20485             if (this.before) {
20486                 inputblock.cn.push({
20487                     tag :'span',
20488                     cls : 'input-group-addon',
20489                     html : this.before
20490                 });
20491             }
20492             
20493             inputblock.cn.push(input);
20494             
20495             if(this.inputType != 'radio'){
20496                 inputblock.cn.push(hidden);
20497             }
20498             
20499             if (this.after) {
20500                 inputblock.cn.push({
20501                     tag :'span',
20502                     cls : 'input-group-addon',
20503                     html : this.after
20504                 });
20505             }
20506             
20507         }
20508         
20509         if (align ==='left' && this.fieldLabel.length) {
20510 //                Roo.log("left and has label");
20511             cfg.cn = [
20512                 {
20513                     tag: 'label',
20514                     'for' :  id,
20515                     cls : 'control-label',
20516                     html : this.fieldLabel
20517                 },
20518                 {
20519                     cls : "", 
20520                     cn: [
20521                         inputblock
20522                     ]
20523                 }
20524             ];
20525             
20526             if(this.labelWidth > 12){
20527                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20528             }
20529             
20530             if(this.labelWidth < 13 && this.labelmd == 0){
20531                 this.labelmd = this.labelWidth;
20532             }
20533             
20534             if(this.labellg > 0){
20535                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20536                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20537             }
20538             
20539             if(this.labelmd > 0){
20540                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20541                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20542             }
20543             
20544             if(this.labelsm > 0){
20545                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20546                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20547             }
20548             
20549             if(this.labelxs > 0){
20550                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20551                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20552             }
20553             
20554         } else if ( this.fieldLabel.length) {
20555 //                Roo.log(" label");
20556                 cfg.cn = [
20557                    
20558                     {
20559                         tag: this.boxLabel ? 'span' : 'label',
20560                         'for': id,
20561                         cls: 'control-label box-input-label',
20562                         //cls : 'input-group-addon',
20563                         html : this.fieldLabel
20564                     },
20565                     
20566                     inputblock
20567                     
20568                 ];
20569
20570         } else {
20571             
20572 //                Roo.log(" no label && no align");
20573                 cfg.cn = [  inputblock ] ;
20574                 
20575                 
20576         }
20577         
20578         if(this.boxLabel){
20579              var boxLabelCfg = {
20580                 tag: 'label',
20581                 //'for': id, // box label is handled by onclick - so no for...
20582                 cls: 'box-label',
20583                 html: this.boxLabel
20584             };
20585             
20586             if(this.tooltip){
20587                 boxLabelCfg.tooltip = this.tooltip;
20588             }
20589              
20590             cfg.cn.push(boxLabelCfg);
20591         }
20592         
20593         if(this.inputType != 'radio'){
20594             cfg.cn.push(hidden);
20595         }
20596         
20597         return cfg;
20598         
20599     },
20600     
20601     /**
20602      * return the real input element.
20603      */
20604     inputEl: function ()
20605     {
20606         return this.el.select('input.roo-' + this.inputType,true).first();
20607     },
20608     hiddenEl: function ()
20609     {
20610         return this.el.select('input.roo-hidden-value',true).first();
20611     },
20612     
20613     labelEl: function()
20614     {
20615         return this.el.select('label.control-label',true).first();
20616     },
20617     /* depricated... */
20618     
20619     label: function()
20620     {
20621         return this.labelEl();
20622     },
20623     
20624     boxLabelEl: function()
20625     {
20626         return this.el.select('label.box-label',true).first();
20627     },
20628     
20629     initEvents : function()
20630     {
20631 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20632         
20633         this.inputEl().on('click', this.onClick,  this);
20634         
20635         if (this.boxLabel) { 
20636             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20637         }
20638         
20639         this.startValue = this.getValue();
20640         
20641         if(this.groupId){
20642             Roo.bootstrap.CheckBox.register(this);
20643         }
20644     },
20645     
20646     onClick : function(e)
20647     {   
20648         if(this.fireEvent('click', this, e) !== false){
20649             this.setChecked(!this.checked);
20650         }
20651         
20652     },
20653     
20654     setChecked : function(state,suppressEvent)
20655     {
20656         this.startValue = this.getValue();
20657
20658         if(this.inputType == 'radio'){
20659             
20660             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20661                 e.dom.checked = false;
20662             });
20663             
20664             this.inputEl().dom.checked = true;
20665             
20666             this.inputEl().dom.value = this.inputValue;
20667             
20668             if(suppressEvent !== true){
20669                 this.fireEvent('check', this, true);
20670             }
20671             
20672             this.validate();
20673             
20674             return;
20675         }
20676         
20677         this.checked = state;
20678         
20679         this.inputEl().dom.checked = state;
20680         
20681         
20682         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20683         
20684         if(suppressEvent !== true){
20685             this.fireEvent('check', this, state);
20686         }
20687         
20688         this.validate();
20689     },
20690     
20691     getValue : function()
20692     {
20693         if(this.inputType == 'radio'){
20694             return this.getGroupValue();
20695         }
20696         
20697         return this.hiddenEl().dom.value;
20698         
20699     },
20700     
20701     getGroupValue : function()
20702     {
20703         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20704             return '';
20705         }
20706         
20707         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20708     },
20709     
20710     setValue : function(v,suppressEvent)
20711     {
20712         if(this.inputType == 'radio'){
20713             this.setGroupValue(v, suppressEvent);
20714             return;
20715         }
20716         
20717         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20718         
20719         this.validate();
20720     },
20721     
20722     setGroupValue : function(v, suppressEvent)
20723     {
20724         this.startValue = this.getValue();
20725         
20726         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20727             e.dom.checked = false;
20728             
20729             if(e.dom.value == v){
20730                 e.dom.checked = true;
20731             }
20732         });
20733         
20734         if(suppressEvent !== true){
20735             this.fireEvent('check', this, true);
20736         }
20737
20738         this.validate();
20739         
20740         return;
20741     },
20742     
20743     validate : function()
20744     {
20745         if(this.getVisibilityEl().hasClass('hidden')){
20746             return true;
20747         }
20748         
20749         if(
20750                 this.disabled || 
20751                 (this.inputType == 'radio' && this.validateRadio()) ||
20752                 (this.inputType == 'checkbox' && this.validateCheckbox())
20753         ){
20754             this.markValid();
20755             return true;
20756         }
20757         
20758         this.markInvalid();
20759         return false;
20760     },
20761     
20762     validateRadio : function()
20763     {
20764         if(this.getVisibilityEl().hasClass('hidden')){
20765             return true;
20766         }
20767         
20768         if(this.allowBlank){
20769             return true;
20770         }
20771         
20772         var valid = false;
20773         
20774         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20775             if(!e.dom.checked){
20776                 return;
20777             }
20778             
20779             valid = true;
20780             
20781             return false;
20782         });
20783         
20784         return valid;
20785     },
20786     
20787     validateCheckbox : function()
20788     {
20789         if(!this.groupId){
20790             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20791             //return (this.getValue() == this.inputValue) ? true : false;
20792         }
20793         
20794         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20795         
20796         if(!group){
20797             return false;
20798         }
20799         
20800         var r = false;
20801         
20802         for(var i in group){
20803             if(group[i].el.isVisible(true)){
20804                 r = false;
20805                 break;
20806             }
20807             
20808             r = true;
20809         }
20810         
20811         for(var i in group){
20812             if(r){
20813                 break;
20814             }
20815             
20816             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20817         }
20818         
20819         return r;
20820     },
20821     
20822     /**
20823      * Mark this field as valid
20824      */
20825     markValid : function()
20826     {
20827         var _this = this;
20828         
20829         this.fireEvent('valid', this);
20830         
20831         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20832         
20833         if(this.groupId){
20834             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20835         }
20836         
20837         if(label){
20838             label.markValid();
20839         }
20840
20841         if(this.inputType == 'radio'){
20842             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20843                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20844                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20845             });
20846             
20847             return;
20848         }
20849
20850         if(!this.groupId){
20851             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20852             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20853             return;
20854         }
20855         
20856         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20857         
20858         if(!group){
20859             return;
20860         }
20861         
20862         for(var i in group){
20863             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20864             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20865         }
20866     },
20867     
20868      /**
20869      * Mark this field as invalid
20870      * @param {String} msg The validation message
20871      */
20872     markInvalid : function(msg)
20873     {
20874         if(this.allowBlank){
20875             return;
20876         }
20877         
20878         var _this = this;
20879         
20880         this.fireEvent('invalid', this, msg);
20881         
20882         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20883         
20884         if(this.groupId){
20885             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20886         }
20887         
20888         if(label){
20889             label.markInvalid();
20890         }
20891             
20892         if(this.inputType == 'radio'){
20893             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20894                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20895                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20896             });
20897             
20898             return;
20899         }
20900         
20901         if(!this.groupId){
20902             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20903             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20904             return;
20905         }
20906         
20907         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20908         
20909         if(!group){
20910             return;
20911         }
20912         
20913         for(var i in group){
20914             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20915             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20916         }
20917         
20918     },
20919     
20920     clearInvalid : function()
20921     {
20922         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20923         
20924         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20925         
20926         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20927         
20928         if (label && label.iconEl) {
20929             label.iconEl.removeClass(label.validClass);
20930             label.iconEl.removeClass(label.invalidClass);
20931         }
20932     },
20933     
20934     disable : function()
20935     {
20936         if(this.inputType != 'radio'){
20937             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20938             return;
20939         }
20940         
20941         var _this = this;
20942         
20943         if(this.rendered){
20944             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20945                 _this.getActionEl().addClass(this.disabledClass);
20946                 e.dom.disabled = true;
20947             });
20948         }
20949         
20950         this.disabled = true;
20951         this.fireEvent("disable", this);
20952         return this;
20953     },
20954
20955     enable : function()
20956     {
20957         if(this.inputType != 'radio'){
20958             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20959             return;
20960         }
20961         
20962         var _this = this;
20963         
20964         if(this.rendered){
20965             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20966                 _this.getActionEl().removeClass(this.disabledClass);
20967                 e.dom.disabled = false;
20968             });
20969         }
20970         
20971         this.disabled = false;
20972         this.fireEvent("enable", this);
20973         return this;
20974     },
20975     
20976     setBoxLabel : function(v)
20977     {
20978         this.boxLabel = v;
20979         
20980         if(this.rendered){
20981             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20982         }
20983     }
20984
20985 });
20986
20987 Roo.apply(Roo.bootstrap.CheckBox, {
20988     
20989     groups: {},
20990     
20991      /**
20992     * register a CheckBox Group
20993     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
20994     */
20995     register : function(checkbox)
20996     {
20997         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
20998             this.groups[checkbox.groupId] = {};
20999         }
21000         
21001         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21002             return;
21003         }
21004         
21005         this.groups[checkbox.groupId][checkbox.name] = checkbox;
21006         
21007     },
21008     /**
21009     * fetch a CheckBox Group based on the group ID
21010     * @param {string} the group ID
21011     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21012     */
21013     get: function(groupId) {
21014         if (typeof(this.groups[groupId]) == 'undefined') {
21015             return false;
21016         }
21017         
21018         return this.groups[groupId] ;
21019     }
21020     
21021     
21022 });
21023 /*
21024  * - LGPL
21025  *
21026  * RadioItem
21027  * 
21028  */
21029
21030 /**
21031  * @class Roo.bootstrap.Radio
21032  * @extends Roo.bootstrap.Component
21033  * Bootstrap Radio class
21034  * @cfg {String} boxLabel - the label associated
21035  * @cfg {String} value - the value of radio
21036  * 
21037  * @constructor
21038  * Create a new Radio
21039  * @param {Object} config The config object
21040  */
21041 Roo.bootstrap.Radio = function(config){
21042     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21043     
21044 };
21045
21046 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21047     
21048     boxLabel : '',
21049     
21050     value : '',
21051     
21052     getAutoCreate : function()
21053     {
21054         var cfg = {
21055             tag : 'div',
21056             cls : 'form-group radio',
21057             cn : [
21058                 {
21059                     tag : 'label',
21060                     cls : 'box-label',
21061                     html : this.boxLabel
21062                 }
21063             ]
21064         };
21065         
21066         return cfg;
21067     },
21068     
21069     initEvents : function() 
21070     {
21071         this.parent().register(this);
21072         
21073         this.el.on('click', this.onClick, this);
21074         
21075     },
21076     
21077     onClick : function(e)
21078     {
21079         if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21080             this.setChecked(true);
21081         }
21082     },
21083     
21084     setChecked : function(state, suppressEvent)
21085     {
21086         this.parent().setValue(this.value, suppressEvent);
21087         
21088     },
21089     
21090     setBoxLabel : function(v)
21091     {
21092         this.boxLabel = v;
21093         
21094         if(this.rendered){
21095             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21096         }
21097     }
21098     
21099 });
21100  
21101
21102  /*
21103  * - LGPL
21104  *
21105  * Input
21106  * 
21107  */
21108
21109 /**
21110  * @class Roo.bootstrap.SecurePass
21111  * @extends Roo.bootstrap.Input
21112  * Bootstrap SecurePass class
21113  *
21114  * 
21115  * @constructor
21116  * Create a new SecurePass
21117  * @param {Object} config The config object
21118  */
21119  
21120 Roo.bootstrap.SecurePass = function (config) {
21121     // these go here, so the translation tool can replace them..
21122     this.errors = {
21123         PwdEmpty: "Please type a password, and then retype it to confirm.",
21124         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21125         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21126         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21127         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21128         FNInPwd: "Your password can't contain your first name. Please type a different password.",
21129         LNInPwd: "Your password can't contain your last name. Please type a different password.",
21130         TooWeak: "Your password is Too Weak."
21131     },
21132     this.meterLabel = "Password strength:";
21133     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21134     this.meterClass = [
21135         "roo-password-meter-tooweak", 
21136         "roo-password-meter-weak", 
21137         "roo-password-meter-medium", 
21138         "roo-password-meter-strong", 
21139         "roo-password-meter-grey"
21140     ];
21141     
21142     this.errors = {};
21143     
21144     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21145 }
21146
21147 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21148     /**
21149      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21150      * {
21151      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
21152      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21153      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21154      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21155      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21156      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
21157      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
21158      * })
21159      */
21160     // private
21161     
21162     meterWidth: 300,
21163     errorMsg :'',    
21164     errors: false,
21165     imageRoot: '/',
21166     /**
21167      * @cfg {String/Object} Label for the strength meter (defaults to
21168      * 'Password strength:')
21169      */
21170     // private
21171     meterLabel: '',
21172     /**
21173      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21174      * ['Weak', 'Medium', 'Strong'])
21175      */
21176     // private    
21177     pwdStrengths: false,    
21178     // private
21179     strength: 0,
21180     // private
21181     _lastPwd: null,
21182     // private
21183     kCapitalLetter: 0,
21184     kSmallLetter: 1,
21185     kDigit: 2,
21186     kPunctuation: 3,
21187     
21188     insecure: false,
21189     // private
21190     initEvents: function ()
21191     {
21192         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21193
21194         if (this.el.is('input[type=password]') && Roo.isSafari) {
21195             this.el.on('keydown', this.SafariOnKeyDown, this);
21196         }
21197
21198         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21199     },
21200     // private
21201     onRender: function (ct, position)
21202     {
21203         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21204         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21205         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21206
21207         this.trigger.createChild({
21208                    cn: [
21209                     {
21210                     //id: 'PwdMeter',
21211                     tag: 'div',
21212                     cls: 'roo-password-meter-grey col-xs-12',
21213                     style: {
21214                         //width: 0,
21215                         //width: this.meterWidth + 'px'                                                
21216                         }
21217                     },
21218                     {                            
21219                          cls: 'roo-password-meter-text'                          
21220                     }
21221                 ]            
21222         });
21223
21224          
21225         if (this.hideTrigger) {
21226             this.trigger.setDisplayed(false);
21227         }
21228         this.setSize(this.width || '', this.height || '');
21229     },
21230     // private
21231     onDestroy: function ()
21232     {
21233         if (this.trigger) {
21234             this.trigger.removeAllListeners();
21235             this.trigger.remove();
21236         }
21237         if (this.wrap) {
21238             this.wrap.remove();
21239         }
21240         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21241     },
21242     // private
21243     checkStrength: function ()
21244     {
21245         var pwd = this.inputEl().getValue();
21246         if (pwd == this._lastPwd) {
21247             return;
21248         }
21249
21250         var strength;
21251         if (this.ClientSideStrongPassword(pwd)) {
21252             strength = 3;
21253         } else if (this.ClientSideMediumPassword(pwd)) {
21254             strength = 2;
21255         } else if (this.ClientSideWeakPassword(pwd)) {
21256             strength = 1;
21257         } else {
21258             strength = 0;
21259         }
21260         
21261         Roo.log('strength1: ' + strength);
21262         
21263         //var pm = this.trigger.child('div/div/div').dom;
21264         var pm = this.trigger.child('div/div');
21265         pm.removeClass(this.meterClass);
21266         pm.addClass(this.meterClass[strength]);
21267                 
21268         
21269         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21270                 
21271         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21272         
21273         this._lastPwd = pwd;
21274     },
21275     reset: function ()
21276     {
21277         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21278         
21279         this._lastPwd = '';
21280         
21281         var pm = this.trigger.child('div/div');
21282         pm.removeClass(this.meterClass);
21283         pm.addClass('roo-password-meter-grey');        
21284         
21285         
21286         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21287         
21288         pt.innerHTML = '';
21289         this.inputEl().dom.type='password';
21290     },
21291     // private
21292     validateValue: function (value)
21293     {
21294         
21295         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21296             return false;
21297         }
21298         if (value.length == 0) {
21299             if (this.allowBlank) {
21300                 this.clearInvalid();
21301                 return true;
21302             }
21303
21304             this.markInvalid(this.errors.PwdEmpty);
21305             this.errorMsg = this.errors.PwdEmpty;
21306             return false;
21307         }
21308         
21309         if(this.insecure){
21310             return true;
21311         }
21312         
21313         if ('[\x21-\x7e]*'.match(value)) {
21314             this.markInvalid(this.errors.PwdBadChar);
21315             this.errorMsg = this.errors.PwdBadChar;
21316             return false;
21317         }
21318         if (value.length < 6) {
21319             this.markInvalid(this.errors.PwdShort);
21320             this.errorMsg = this.errors.PwdShort;
21321             return false;
21322         }
21323         if (value.length > 16) {
21324             this.markInvalid(this.errors.PwdLong);
21325             this.errorMsg = this.errors.PwdLong;
21326             return false;
21327         }
21328         var strength;
21329         if (this.ClientSideStrongPassword(value)) {
21330             strength = 3;
21331         } else if (this.ClientSideMediumPassword(value)) {
21332             strength = 2;
21333         } else if (this.ClientSideWeakPassword(value)) {
21334             strength = 1;
21335         } else {
21336             strength = 0;
21337         }
21338
21339         
21340         if (strength < 2) {
21341             //this.markInvalid(this.errors.TooWeak);
21342             this.errorMsg = this.errors.TooWeak;
21343             //return false;
21344         }
21345         
21346         
21347         console.log('strength2: ' + strength);
21348         
21349         //var pm = this.trigger.child('div/div/div').dom;
21350         
21351         var pm = this.trigger.child('div/div');
21352         pm.removeClass(this.meterClass);
21353         pm.addClass(this.meterClass[strength]);
21354                 
21355         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21356                 
21357         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21358         
21359         this.errorMsg = ''; 
21360         return true;
21361     },
21362     // private
21363     CharacterSetChecks: function (type)
21364     {
21365         this.type = type;
21366         this.fResult = false;
21367     },
21368     // private
21369     isctype: function (character, type)
21370     {
21371         switch (type) {  
21372             case this.kCapitalLetter:
21373                 if (character >= 'A' && character <= 'Z') {
21374                     return true;
21375                 }
21376                 break;
21377             
21378             case this.kSmallLetter:
21379                 if (character >= 'a' && character <= 'z') {
21380                     return true;
21381                 }
21382                 break;
21383             
21384             case this.kDigit:
21385                 if (character >= '0' && character <= '9') {
21386                     return true;
21387                 }
21388                 break;
21389             
21390             case this.kPunctuation:
21391                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21392                     return true;
21393                 }
21394                 break;
21395             
21396             default:
21397                 return false;
21398         }
21399
21400     },
21401     // private
21402     IsLongEnough: function (pwd, size)
21403     {
21404         return !(pwd == null || isNaN(size) || pwd.length < size);
21405     },
21406     // private
21407     SpansEnoughCharacterSets: function (word, nb)
21408     {
21409         if (!this.IsLongEnough(word, nb))
21410         {
21411             return false;
21412         }
21413
21414         var characterSetChecks = new Array(
21415             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21416             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21417         );
21418         
21419         for (var index = 0; index < word.length; ++index) {
21420             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21421                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21422                     characterSetChecks[nCharSet].fResult = true;
21423                     break;
21424                 }
21425             }
21426         }
21427
21428         var nCharSets = 0;
21429         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21430             if (characterSetChecks[nCharSet].fResult) {
21431                 ++nCharSets;
21432             }
21433         }
21434
21435         if (nCharSets < nb) {
21436             return false;
21437         }
21438         return true;
21439     },
21440     // private
21441     ClientSideStrongPassword: function (pwd)
21442     {
21443         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21444     },
21445     // private
21446     ClientSideMediumPassword: function (pwd)
21447     {
21448         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21449     },
21450     // private
21451     ClientSideWeakPassword: function (pwd)
21452     {
21453         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21454     }
21455           
21456 })//<script type="text/javascript">
21457
21458 /*
21459  * Based  Ext JS Library 1.1.1
21460  * Copyright(c) 2006-2007, Ext JS, LLC.
21461  * LGPL
21462  *
21463  */
21464  
21465 /**
21466  * @class Roo.HtmlEditorCore
21467  * @extends Roo.Component
21468  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21469  *
21470  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21471  */
21472
21473 Roo.HtmlEditorCore = function(config){
21474     
21475     
21476     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21477     
21478     
21479     this.addEvents({
21480         /**
21481          * @event initialize
21482          * Fires when the editor is fully initialized (including the iframe)
21483          * @param {Roo.HtmlEditorCore} this
21484          */
21485         initialize: true,
21486         /**
21487          * @event activate
21488          * Fires when the editor is first receives the focus. Any insertion must wait
21489          * until after this event.
21490          * @param {Roo.HtmlEditorCore} this
21491          */
21492         activate: true,
21493          /**
21494          * @event beforesync
21495          * Fires before the textarea is updated with content from the editor iframe. Return false
21496          * to cancel the sync.
21497          * @param {Roo.HtmlEditorCore} this
21498          * @param {String} html
21499          */
21500         beforesync: true,
21501          /**
21502          * @event beforepush
21503          * Fires before the iframe editor is updated with content from the textarea. Return false
21504          * to cancel the push.
21505          * @param {Roo.HtmlEditorCore} this
21506          * @param {String} html
21507          */
21508         beforepush: true,
21509          /**
21510          * @event sync
21511          * Fires when the textarea is updated with content from the editor iframe.
21512          * @param {Roo.HtmlEditorCore} this
21513          * @param {String} html
21514          */
21515         sync: true,
21516          /**
21517          * @event push
21518          * Fires when the iframe editor is updated with content from the textarea.
21519          * @param {Roo.HtmlEditorCore} this
21520          * @param {String} html
21521          */
21522         push: true,
21523         
21524         /**
21525          * @event editorevent
21526          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21527          * @param {Roo.HtmlEditorCore} this
21528          */
21529         editorevent: true
21530         
21531     });
21532     
21533     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21534     
21535     // defaults : white / black...
21536     this.applyBlacklists();
21537     
21538     
21539     
21540 };
21541
21542
21543 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21544
21545
21546      /**
21547      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21548      */
21549     
21550     owner : false,
21551     
21552      /**
21553      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21554      *                        Roo.resizable.
21555      */
21556     resizable : false,
21557      /**
21558      * @cfg {Number} height (in pixels)
21559      */   
21560     height: 300,
21561    /**
21562      * @cfg {Number} width (in pixels)
21563      */   
21564     width: 500,
21565     
21566     /**
21567      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21568      * 
21569      */
21570     stylesheets: false,
21571     
21572     // id of frame..
21573     frameId: false,
21574     
21575     // private properties
21576     validationEvent : false,
21577     deferHeight: true,
21578     initialized : false,
21579     activated : false,
21580     sourceEditMode : false,
21581     onFocus : Roo.emptyFn,
21582     iframePad:3,
21583     hideMode:'offsets',
21584     
21585     clearUp: true,
21586     
21587     // blacklist + whitelisted elements..
21588     black: false,
21589     white: false,
21590      
21591     bodyCls : '',
21592
21593     /**
21594      * Protected method that will not generally be called directly. It
21595      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21596      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21597      */
21598     getDocMarkup : function(){
21599         // body styles..
21600         var st = '';
21601         
21602         // inherit styels from page...?? 
21603         if (this.stylesheets === false) {
21604             
21605             Roo.get(document.head).select('style').each(function(node) {
21606                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21607             });
21608             
21609             Roo.get(document.head).select('link').each(function(node) { 
21610                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21611             });
21612             
21613         } else if (!this.stylesheets.length) {
21614                 // simple..
21615                 st = '<style type="text/css">' +
21616                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21617                    '</style>';
21618         } else { 
21619             st = '<style type="text/css">' +
21620                     this.stylesheets +
21621                 '</style>';
21622         }
21623         
21624         st +=  '<style type="text/css">' +
21625             'IMG { cursor: pointer } ' +
21626         '</style>';
21627
21628         var cls = 'roo-htmleditor-body';
21629         
21630         if(this.bodyCls.length){
21631             cls += ' ' + this.bodyCls;
21632         }
21633         
21634         return '<html><head>' + st  +
21635             //<style type="text/css">' +
21636             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21637             //'</style>' +
21638             ' </head><body class="' +  cls + '"></body></html>';
21639     },
21640
21641     // private
21642     onRender : function(ct, position)
21643     {
21644         var _t = this;
21645         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21646         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21647         
21648         
21649         this.el.dom.style.border = '0 none';
21650         this.el.dom.setAttribute('tabIndex', -1);
21651         this.el.addClass('x-hidden hide');
21652         
21653         
21654         
21655         if(Roo.isIE){ // fix IE 1px bogus margin
21656             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21657         }
21658        
21659         
21660         this.frameId = Roo.id();
21661         
21662          
21663         
21664         var iframe = this.owner.wrap.createChild({
21665             tag: 'iframe',
21666             cls: 'form-control', // bootstrap..
21667             id: this.frameId,
21668             name: this.frameId,
21669             frameBorder : 'no',
21670             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21671         }, this.el
21672         );
21673         
21674         
21675         this.iframe = iframe.dom;
21676
21677          this.assignDocWin();
21678         
21679         this.doc.designMode = 'on';
21680        
21681         this.doc.open();
21682         this.doc.write(this.getDocMarkup());
21683         this.doc.close();
21684
21685         
21686         var task = { // must defer to wait for browser to be ready
21687             run : function(){
21688                 //console.log("run task?" + this.doc.readyState);
21689                 this.assignDocWin();
21690                 if(this.doc.body || this.doc.readyState == 'complete'){
21691                     try {
21692                         this.doc.designMode="on";
21693                     } catch (e) {
21694                         return;
21695                     }
21696                     Roo.TaskMgr.stop(task);
21697                     this.initEditor.defer(10, this);
21698                 }
21699             },
21700             interval : 10,
21701             duration: 10000,
21702             scope: this
21703         };
21704         Roo.TaskMgr.start(task);
21705
21706     },
21707
21708     // private
21709     onResize : function(w, h)
21710     {
21711          Roo.log('resize: ' +w + ',' + h );
21712         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21713         if(!this.iframe){
21714             return;
21715         }
21716         if(typeof w == 'number'){
21717             
21718             this.iframe.style.width = w + 'px';
21719         }
21720         if(typeof h == 'number'){
21721             
21722             this.iframe.style.height = h + 'px';
21723             if(this.doc){
21724                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21725             }
21726         }
21727         
21728     },
21729
21730     /**
21731      * Toggles the editor between standard and source edit mode.
21732      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21733      */
21734     toggleSourceEdit : function(sourceEditMode){
21735         
21736         this.sourceEditMode = sourceEditMode === true;
21737         
21738         if(this.sourceEditMode){
21739  
21740             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21741             
21742         }else{
21743             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21744             //this.iframe.className = '';
21745             this.deferFocus();
21746         }
21747         //this.setSize(this.owner.wrap.getSize());
21748         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21749     },
21750
21751     
21752   
21753
21754     /**
21755      * Protected method that will not generally be called directly. If you need/want
21756      * custom HTML cleanup, this is the method you should override.
21757      * @param {String} html The HTML to be cleaned
21758      * return {String} The cleaned HTML
21759      */
21760     cleanHtml : function(html){
21761         html = String(html);
21762         if(html.length > 5){
21763             if(Roo.isSafari){ // strip safari nonsense
21764                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21765             }
21766         }
21767         if(html == '&nbsp;'){
21768             html = '';
21769         }
21770         return html;
21771     },
21772
21773     /**
21774      * HTML Editor -> Textarea
21775      * Protected method that will not generally be called directly. Syncs the contents
21776      * of the editor iframe with the textarea.
21777      */
21778     syncValue : function(){
21779         if(this.initialized){
21780             var bd = (this.doc.body || this.doc.documentElement);
21781             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21782             var html = bd.innerHTML;
21783             if(Roo.isSafari){
21784                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21785                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21786                 if(m && m[1]){
21787                     html = '<div style="'+m[0]+'">' + html + '</div>';
21788                 }
21789             }
21790             html = this.cleanHtml(html);
21791             // fix up the special chars.. normaly like back quotes in word...
21792             // however we do not want to do this with chinese..
21793             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21794                 var cc = b.charCodeAt();
21795                 if (
21796                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21797                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21798                     (cc >= 0xf900 && cc < 0xfb00 )
21799                 ) {
21800                         return b;
21801                 }
21802                 return "&#"+cc+";" 
21803             });
21804             if(this.owner.fireEvent('beforesync', this, html) !== false){
21805                 this.el.dom.value = html;
21806                 this.owner.fireEvent('sync', this, html);
21807             }
21808         }
21809     },
21810
21811     /**
21812      * Protected method that will not generally be called directly. Pushes the value of the textarea
21813      * into the iframe editor.
21814      */
21815     pushValue : function(){
21816         if(this.initialized){
21817             var v = this.el.dom.value.trim();
21818             
21819 //            if(v.length < 1){
21820 //                v = '&#160;';
21821 //            }
21822             
21823             if(this.owner.fireEvent('beforepush', this, v) !== false){
21824                 var d = (this.doc.body || this.doc.documentElement);
21825                 d.innerHTML = v;
21826                 this.cleanUpPaste();
21827                 this.el.dom.value = d.innerHTML;
21828                 this.owner.fireEvent('push', this, v);
21829             }
21830         }
21831     },
21832
21833     // private
21834     deferFocus : function(){
21835         this.focus.defer(10, this);
21836     },
21837
21838     // doc'ed in Field
21839     focus : function(){
21840         if(this.win && !this.sourceEditMode){
21841             this.win.focus();
21842         }else{
21843             this.el.focus();
21844         }
21845     },
21846     
21847     assignDocWin: function()
21848     {
21849         var iframe = this.iframe;
21850         
21851          if(Roo.isIE){
21852             this.doc = iframe.contentWindow.document;
21853             this.win = iframe.contentWindow;
21854         } else {
21855 //            if (!Roo.get(this.frameId)) {
21856 //                return;
21857 //            }
21858 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21859 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21860             
21861             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21862                 return;
21863             }
21864             
21865             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21866             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21867         }
21868     },
21869     
21870     // private
21871     initEditor : function(){
21872         //console.log("INIT EDITOR");
21873         this.assignDocWin();
21874         
21875         
21876         
21877         this.doc.designMode="on";
21878         this.doc.open();
21879         this.doc.write(this.getDocMarkup());
21880         this.doc.close();
21881         
21882         var dbody = (this.doc.body || this.doc.documentElement);
21883         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21884         // this copies styles from the containing element into thsi one..
21885         // not sure why we need all of this..
21886         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21887         
21888         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21889         //ss['background-attachment'] = 'fixed'; // w3c
21890         dbody.bgProperties = 'fixed'; // ie
21891         //Roo.DomHelper.applyStyles(dbody, ss);
21892         Roo.EventManager.on(this.doc, {
21893             //'mousedown': this.onEditorEvent,
21894             'mouseup': this.onEditorEvent,
21895             'dblclick': this.onEditorEvent,
21896             'click': this.onEditorEvent,
21897             'keyup': this.onEditorEvent,
21898             buffer:100,
21899             scope: this
21900         });
21901         if(Roo.isGecko){
21902             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21903         }
21904         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21905             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21906         }
21907         this.initialized = true;
21908
21909         this.owner.fireEvent('initialize', this);
21910         this.pushValue();
21911     },
21912
21913     // private
21914     onDestroy : function(){
21915         
21916         
21917         
21918         if(this.rendered){
21919             
21920             //for (var i =0; i < this.toolbars.length;i++) {
21921             //    // fixme - ask toolbars for heights?
21922             //    this.toolbars[i].onDestroy();
21923            // }
21924             
21925             //this.wrap.dom.innerHTML = '';
21926             //this.wrap.remove();
21927         }
21928     },
21929
21930     // private
21931     onFirstFocus : function(){
21932         
21933         this.assignDocWin();
21934         
21935         
21936         this.activated = true;
21937          
21938     
21939         if(Roo.isGecko){ // prevent silly gecko errors
21940             this.win.focus();
21941             var s = this.win.getSelection();
21942             if(!s.focusNode || s.focusNode.nodeType != 3){
21943                 var r = s.getRangeAt(0);
21944                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21945                 r.collapse(true);
21946                 this.deferFocus();
21947             }
21948             try{
21949                 this.execCmd('useCSS', true);
21950                 this.execCmd('styleWithCSS', false);
21951             }catch(e){}
21952         }
21953         this.owner.fireEvent('activate', this);
21954     },
21955
21956     // private
21957     adjustFont: function(btn){
21958         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21959         //if(Roo.isSafari){ // safari
21960         //    adjust *= 2;
21961        // }
21962         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21963         if(Roo.isSafari){ // safari
21964             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21965             v =  (v < 10) ? 10 : v;
21966             v =  (v > 48) ? 48 : v;
21967             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21968             
21969         }
21970         
21971         
21972         v = Math.max(1, v+adjust);
21973         
21974         this.execCmd('FontSize', v  );
21975     },
21976
21977     onEditorEvent : function(e)
21978     {
21979         this.owner.fireEvent('editorevent', this, e);
21980       //  this.updateToolbar();
21981         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21982     },
21983
21984     insertTag : function(tg)
21985     {
21986         // could be a bit smarter... -> wrap the current selected tRoo..
21987         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21988             
21989             range = this.createRange(this.getSelection());
21990             var wrappingNode = this.doc.createElement(tg.toLowerCase());
21991             wrappingNode.appendChild(range.extractContents());
21992             range.insertNode(wrappingNode);
21993
21994             return;
21995             
21996             
21997             
21998         }
21999         this.execCmd("formatblock",   tg);
22000         
22001     },
22002     
22003     insertText : function(txt)
22004     {
22005         
22006         
22007         var range = this.createRange();
22008         range.deleteContents();
22009                //alert(Sender.getAttribute('label'));
22010                
22011         range.insertNode(this.doc.createTextNode(txt));
22012     } ,
22013     
22014      
22015
22016     /**
22017      * Executes a Midas editor command on the editor document and performs necessary focus and
22018      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22019      * @param {String} cmd The Midas command
22020      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22021      */
22022     relayCmd : function(cmd, value){
22023         this.win.focus();
22024         this.execCmd(cmd, value);
22025         this.owner.fireEvent('editorevent', this);
22026         //this.updateToolbar();
22027         this.owner.deferFocus();
22028     },
22029
22030     /**
22031      * Executes a Midas editor command directly on the editor document.
22032      * For visual commands, you should use {@link #relayCmd} instead.
22033      * <b>This should only be called after the editor is initialized.</b>
22034      * @param {String} cmd The Midas command
22035      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22036      */
22037     execCmd : function(cmd, value){
22038         this.doc.execCommand(cmd, false, value === undefined ? null : value);
22039         this.syncValue();
22040     },
22041  
22042  
22043    
22044     /**
22045      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22046      * to insert tRoo.
22047      * @param {String} text | dom node.. 
22048      */
22049     insertAtCursor : function(text)
22050     {
22051         
22052         if(!this.activated){
22053             return;
22054         }
22055         /*
22056         if(Roo.isIE){
22057             this.win.focus();
22058             var r = this.doc.selection.createRange();
22059             if(r){
22060                 r.collapse(true);
22061                 r.pasteHTML(text);
22062                 this.syncValue();
22063                 this.deferFocus();
22064             
22065             }
22066             return;
22067         }
22068         */
22069         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22070             this.win.focus();
22071             
22072             
22073             // from jquery ui (MIT licenced)
22074             var range, node;
22075             var win = this.win;
22076             
22077             if (win.getSelection && win.getSelection().getRangeAt) {
22078                 range = win.getSelection().getRangeAt(0);
22079                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22080                 range.insertNode(node);
22081             } else if (win.document.selection && win.document.selection.createRange) {
22082                 // no firefox support
22083                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22084                 win.document.selection.createRange().pasteHTML(txt);
22085             } else {
22086                 // no firefox support
22087                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22088                 this.execCmd('InsertHTML', txt);
22089             } 
22090             
22091             this.syncValue();
22092             
22093             this.deferFocus();
22094         }
22095     },
22096  // private
22097     mozKeyPress : function(e){
22098         if(e.ctrlKey){
22099             var c = e.getCharCode(), cmd;
22100           
22101             if(c > 0){
22102                 c = String.fromCharCode(c).toLowerCase();
22103                 switch(c){
22104                     case 'b':
22105                         cmd = 'bold';
22106                         break;
22107                     case 'i':
22108                         cmd = 'italic';
22109                         break;
22110                     
22111                     case 'u':
22112                         cmd = 'underline';
22113                         break;
22114                     
22115                     case 'v':
22116                         this.cleanUpPaste.defer(100, this);
22117                         return;
22118                         
22119                 }
22120                 if(cmd){
22121                     this.win.focus();
22122                     this.execCmd(cmd);
22123                     this.deferFocus();
22124                     e.preventDefault();
22125                 }
22126                 
22127             }
22128         }
22129     },
22130
22131     // private
22132     fixKeys : function(){ // load time branching for fastest keydown performance
22133         if(Roo.isIE){
22134             return function(e){
22135                 var k = e.getKey(), r;
22136                 if(k == e.TAB){
22137                     e.stopEvent();
22138                     r = this.doc.selection.createRange();
22139                     if(r){
22140                         r.collapse(true);
22141                         r.pasteHTML('&#160;&#160;&#160;&#160;');
22142                         this.deferFocus();
22143                     }
22144                     return;
22145                 }
22146                 
22147                 if(k == e.ENTER){
22148                     r = this.doc.selection.createRange();
22149                     if(r){
22150                         var target = r.parentElement();
22151                         if(!target || target.tagName.toLowerCase() != 'li'){
22152                             e.stopEvent();
22153                             r.pasteHTML('<br />');
22154                             r.collapse(false);
22155                             r.select();
22156                         }
22157                     }
22158                 }
22159                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22160                     this.cleanUpPaste.defer(100, this);
22161                     return;
22162                 }
22163                 
22164                 
22165             };
22166         }else if(Roo.isOpera){
22167             return function(e){
22168                 var k = e.getKey();
22169                 if(k == e.TAB){
22170                     e.stopEvent();
22171                     this.win.focus();
22172                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
22173                     this.deferFocus();
22174                 }
22175                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22176                     this.cleanUpPaste.defer(100, this);
22177                     return;
22178                 }
22179                 
22180             };
22181         }else if(Roo.isSafari){
22182             return function(e){
22183                 var k = e.getKey();
22184                 
22185                 if(k == e.TAB){
22186                     e.stopEvent();
22187                     this.execCmd('InsertText','\t');
22188                     this.deferFocus();
22189                     return;
22190                 }
22191                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22192                     this.cleanUpPaste.defer(100, this);
22193                     return;
22194                 }
22195                 
22196              };
22197         }
22198     }(),
22199     
22200     getAllAncestors: function()
22201     {
22202         var p = this.getSelectedNode();
22203         var a = [];
22204         if (!p) {
22205             a.push(p); // push blank onto stack..
22206             p = this.getParentElement();
22207         }
22208         
22209         
22210         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22211             a.push(p);
22212             p = p.parentNode;
22213         }
22214         a.push(this.doc.body);
22215         return a;
22216     },
22217     lastSel : false,
22218     lastSelNode : false,
22219     
22220     
22221     getSelection : function() 
22222     {
22223         this.assignDocWin();
22224         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22225     },
22226     
22227     getSelectedNode: function() 
22228     {
22229         // this may only work on Gecko!!!
22230         
22231         // should we cache this!!!!
22232         
22233         
22234         
22235          
22236         var range = this.createRange(this.getSelection()).cloneRange();
22237         
22238         if (Roo.isIE) {
22239             var parent = range.parentElement();
22240             while (true) {
22241                 var testRange = range.duplicate();
22242                 testRange.moveToElementText(parent);
22243                 if (testRange.inRange(range)) {
22244                     break;
22245                 }
22246                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22247                     break;
22248                 }
22249                 parent = parent.parentElement;
22250             }
22251             return parent;
22252         }
22253         
22254         // is ancestor a text element.
22255         var ac =  range.commonAncestorContainer;
22256         if (ac.nodeType == 3) {
22257             ac = ac.parentNode;
22258         }
22259         
22260         var ar = ac.childNodes;
22261          
22262         var nodes = [];
22263         var other_nodes = [];
22264         var has_other_nodes = false;
22265         for (var i=0;i<ar.length;i++) {
22266             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22267                 continue;
22268             }
22269             // fullly contained node.
22270             
22271             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22272                 nodes.push(ar[i]);
22273                 continue;
22274             }
22275             
22276             // probably selected..
22277             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22278                 other_nodes.push(ar[i]);
22279                 continue;
22280             }
22281             // outer..
22282             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22283                 continue;
22284             }
22285             
22286             
22287             has_other_nodes = true;
22288         }
22289         if (!nodes.length && other_nodes.length) {
22290             nodes= other_nodes;
22291         }
22292         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22293             return false;
22294         }
22295         
22296         return nodes[0];
22297     },
22298     createRange: function(sel)
22299     {
22300         // this has strange effects when using with 
22301         // top toolbar - not sure if it's a great idea.
22302         //this.editor.contentWindow.focus();
22303         if (typeof sel != "undefined") {
22304             try {
22305                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22306             } catch(e) {
22307                 return this.doc.createRange();
22308             }
22309         } else {
22310             return this.doc.createRange();
22311         }
22312     },
22313     getParentElement: function()
22314     {
22315         
22316         this.assignDocWin();
22317         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22318         
22319         var range = this.createRange(sel);
22320          
22321         try {
22322             var p = range.commonAncestorContainer;
22323             while (p.nodeType == 3) { // text node
22324                 p = p.parentNode;
22325             }
22326             return p;
22327         } catch (e) {
22328             return null;
22329         }
22330     
22331     },
22332     /***
22333      *
22334      * Range intersection.. the hard stuff...
22335      *  '-1' = before
22336      *  '0' = hits..
22337      *  '1' = after.
22338      *         [ -- selected range --- ]
22339      *   [fail]                        [fail]
22340      *
22341      *    basically..
22342      *      if end is before start or  hits it. fail.
22343      *      if start is after end or hits it fail.
22344      *
22345      *   if either hits (but other is outside. - then it's not 
22346      *   
22347      *    
22348      **/
22349     
22350     
22351     // @see http://www.thismuchiknow.co.uk/?p=64.
22352     rangeIntersectsNode : function(range, node)
22353     {
22354         var nodeRange = node.ownerDocument.createRange();
22355         try {
22356             nodeRange.selectNode(node);
22357         } catch (e) {
22358             nodeRange.selectNodeContents(node);
22359         }
22360     
22361         var rangeStartRange = range.cloneRange();
22362         rangeStartRange.collapse(true);
22363     
22364         var rangeEndRange = range.cloneRange();
22365         rangeEndRange.collapse(false);
22366     
22367         var nodeStartRange = nodeRange.cloneRange();
22368         nodeStartRange.collapse(true);
22369     
22370         var nodeEndRange = nodeRange.cloneRange();
22371         nodeEndRange.collapse(false);
22372     
22373         return rangeStartRange.compareBoundaryPoints(
22374                  Range.START_TO_START, nodeEndRange) == -1 &&
22375                rangeEndRange.compareBoundaryPoints(
22376                  Range.START_TO_START, nodeStartRange) == 1;
22377         
22378          
22379     },
22380     rangeCompareNode : function(range, node)
22381     {
22382         var nodeRange = node.ownerDocument.createRange();
22383         try {
22384             nodeRange.selectNode(node);
22385         } catch (e) {
22386             nodeRange.selectNodeContents(node);
22387         }
22388         
22389         
22390         range.collapse(true);
22391     
22392         nodeRange.collapse(true);
22393      
22394         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22395         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22396          
22397         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22398         
22399         var nodeIsBefore   =  ss == 1;
22400         var nodeIsAfter    = ee == -1;
22401         
22402         if (nodeIsBefore && nodeIsAfter) {
22403             return 0; // outer
22404         }
22405         if (!nodeIsBefore && nodeIsAfter) {
22406             return 1; //right trailed.
22407         }
22408         
22409         if (nodeIsBefore && !nodeIsAfter) {
22410             return 2;  // left trailed.
22411         }
22412         // fully contined.
22413         return 3;
22414     },
22415
22416     // private? - in a new class?
22417     cleanUpPaste :  function()
22418     {
22419         // cleans up the whole document..
22420         Roo.log('cleanuppaste');
22421         
22422         this.cleanUpChildren(this.doc.body);
22423         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22424         if (clean != this.doc.body.innerHTML) {
22425             this.doc.body.innerHTML = clean;
22426         }
22427         
22428     },
22429     
22430     cleanWordChars : function(input) {// change the chars to hex code
22431         var he = Roo.HtmlEditorCore;
22432         
22433         var output = input;
22434         Roo.each(he.swapCodes, function(sw) { 
22435             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22436             
22437             output = output.replace(swapper, sw[1]);
22438         });
22439         
22440         return output;
22441     },
22442     
22443     
22444     cleanUpChildren : function (n)
22445     {
22446         if (!n.childNodes.length) {
22447             return;
22448         }
22449         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22450            this.cleanUpChild(n.childNodes[i]);
22451         }
22452     },
22453     
22454     
22455         
22456     
22457     cleanUpChild : function (node)
22458     {
22459         var ed = this;
22460         //console.log(node);
22461         if (node.nodeName == "#text") {
22462             // clean up silly Windows -- stuff?
22463             return; 
22464         }
22465         if (node.nodeName == "#comment") {
22466             node.parentNode.removeChild(node);
22467             // clean up silly Windows -- stuff?
22468             return; 
22469         }
22470         var lcname = node.tagName.toLowerCase();
22471         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22472         // whitelist of tags..
22473         
22474         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22475             // remove node.
22476             node.parentNode.removeChild(node);
22477             return;
22478             
22479         }
22480         
22481         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22482         
22483         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22484         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22485         
22486         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22487         //    remove_keep_children = true;
22488         //}
22489         
22490         if (remove_keep_children) {
22491             this.cleanUpChildren(node);
22492             // inserts everything just before this node...
22493             while (node.childNodes.length) {
22494                 var cn = node.childNodes[0];
22495                 node.removeChild(cn);
22496                 node.parentNode.insertBefore(cn, node);
22497             }
22498             node.parentNode.removeChild(node);
22499             return;
22500         }
22501         
22502         if (!node.attributes || !node.attributes.length) {
22503             this.cleanUpChildren(node);
22504             return;
22505         }
22506         
22507         function cleanAttr(n,v)
22508         {
22509             
22510             if (v.match(/^\./) || v.match(/^\//)) {
22511                 return;
22512             }
22513             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22514                 return;
22515             }
22516             if (v.match(/^#/)) {
22517                 return;
22518             }
22519 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22520             node.removeAttribute(n);
22521             
22522         }
22523         
22524         var cwhite = this.cwhite;
22525         var cblack = this.cblack;
22526             
22527         function cleanStyle(n,v)
22528         {
22529             if (v.match(/expression/)) { //XSS?? should we even bother..
22530                 node.removeAttribute(n);
22531                 return;
22532             }
22533             
22534             var parts = v.split(/;/);
22535             var clean = [];
22536             
22537             Roo.each(parts, function(p) {
22538                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22539                 if (!p.length) {
22540                     return true;
22541                 }
22542                 var l = p.split(':').shift().replace(/\s+/g,'');
22543                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22544                 
22545                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22546 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22547                     //node.removeAttribute(n);
22548                     return true;
22549                 }
22550                 //Roo.log()
22551                 // only allow 'c whitelisted system attributes'
22552                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22553 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22554                     //node.removeAttribute(n);
22555                     return true;
22556                 }
22557                 
22558                 
22559                  
22560                 
22561                 clean.push(p);
22562                 return true;
22563             });
22564             if (clean.length) { 
22565                 node.setAttribute(n, clean.join(';'));
22566             } else {
22567                 node.removeAttribute(n);
22568             }
22569             
22570         }
22571         
22572         
22573         for (var i = node.attributes.length-1; i > -1 ; i--) {
22574             var a = node.attributes[i];
22575             //console.log(a);
22576             
22577             if (a.name.toLowerCase().substr(0,2)=='on')  {
22578                 node.removeAttribute(a.name);
22579                 continue;
22580             }
22581             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22582                 node.removeAttribute(a.name);
22583                 continue;
22584             }
22585             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22586                 cleanAttr(a.name,a.value); // fixme..
22587                 continue;
22588             }
22589             if (a.name == 'style') {
22590                 cleanStyle(a.name,a.value);
22591                 continue;
22592             }
22593             /// clean up MS crap..
22594             // tecnically this should be a list of valid class'es..
22595             
22596             
22597             if (a.name == 'class') {
22598                 if (a.value.match(/^Mso/)) {
22599                     node.className = '';
22600                 }
22601                 
22602                 if (a.value.match(/^body$/)) {
22603                     node.className = '';
22604                 }
22605                 continue;
22606             }
22607             
22608             // style cleanup!?
22609             // class cleanup?
22610             
22611         }
22612         
22613         
22614         this.cleanUpChildren(node);
22615         
22616         
22617     },
22618     
22619     /**
22620      * Clean up MS wordisms...
22621      */
22622     cleanWord : function(node)
22623     {
22624         
22625         
22626         if (!node) {
22627             this.cleanWord(this.doc.body);
22628             return;
22629         }
22630         if (node.nodeName == "#text") {
22631             // clean up silly Windows -- stuff?
22632             return; 
22633         }
22634         if (node.nodeName == "#comment") {
22635             node.parentNode.removeChild(node);
22636             // clean up silly Windows -- stuff?
22637             return; 
22638         }
22639         
22640         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22641             node.parentNode.removeChild(node);
22642             return;
22643         }
22644         
22645         // remove - but keep children..
22646         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22647             while (node.childNodes.length) {
22648                 var cn = node.childNodes[0];
22649                 node.removeChild(cn);
22650                 node.parentNode.insertBefore(cn, node);
22651             }
22652             node.parentNode.removeChild(node);
22653             this.iterateChildren(node, this.cleanWord);
22654             return;
22655         }
22656         // clean styles
22657         if (node.className.length) {
22658             
22659             var cn = node.className.split(/\W+/);
22660             var cna = [];
22661             Roo.each(cn, function(cls) {
22662                 if (cls.match(/Mso[a-zA-Z]+/)) {
22663                     return;
22664                 }
22665                 cna.push(cls);
22666             });
22667             node.className = cna.length ? cna.join(' ') : '';
22668             if (!cna.length) {
22669                 node.removeAttribute("class");
22670             }
22671         }
22672         
22673         if (node.hasAttribute("lang")) {
22674             node.removeAttribute("lang");
22675         }
22676         
22677         if (node.hasAttribute("style")) {
22678             
22679             var styles = node.getAttribute("style").split(";");
22680             var nstyle = [];
22681             Roo.each(styles, function(s) {
22682                 if (!s.match(/:/)) {
22683                     return;
22684                 }
22685                 var kv = s.split(":");
22686                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22687                     return;
22688                 }
22689                 // what ever is left... we allow.
22690                 nstyle.push(s);
22691             });
22692             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22693             if (!nstyle.length) {
22694                 node.removeAttribute('style');
22695             }
22696         }
22697         this.iterateChildren(node, this.cleanWord);
22698         
22699         
22700         
22701     },
22702     /**
22703      * iterateChildren of a Node, calling fn each time, using this as the scole..
22704      * @param {DomNode} node node to iterate children of.
22705      * @param {Function} fn method of this class to call on each item.
22706      */
22707     iterateChildren : function(node, fn)
22708     {
22709         if (!node.childNodes.length) {
22710                 return;
22711         }
22712         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22713            fn.call(this, node.childNodes[i])
22714         }
22715     },
22716     
22717     
22718     /**
22719      * cleanTableWidths.
22720      *
22721      * Quite often pasting from word etc.. results in tables with column and widths.
22722      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22723      *
22724      */
22725     cleanTableWidths : function(node)
22726     {
22727          
22728          
22729         if (!node) {
22730             this.cleanTableWidths(this.doc.body);
22731             return;
22732         }
22733         
22734         // ignore list...
22735         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22736             return; 
22737         }
22738         Roo.log(node.tagName);
22739         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22740             this.iterateChildren(node, this.cleanTableWidths);
22741             return;
22742         }
22743         if (node.hasAttribute('width')) {
22744             node.removeAttribute('width');
22745         }
22746         
22747          
22748         if (node.hasAttribute("style")) {
22749             // pretty basic...
22750             
22751             var styles = node.getAttribute("style").split(";");
22752             var nstyle = [];
22753             Roo.each(styles, function(s) {
22754                 if (!s.match(/:/)) {
22755                     return;
22756                 }
22757                 var kv = s.split(":");
22758                 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22759                     return;
22760                 }
22761                 // what ever is left... we allow.
22762                 nstyle.push(s);
22763             });
22764             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22765             if (!nstyle.length) {
22766                 node.removeAttribute('style');
22767             }
22768         }
22769         
22770         this.iterateChildren(node, this.cleanTableWidths);
22771         
22772         
22773     },
22774     
22775     
22776     
22777     
22778     domToHTML : function(currentElement, depth, nopadtext) {
22779         
22780         depth = depth || 0;
22781         nopadtext = nopadtext || false;
22782     
22783         if (!currentElement) {
22784             return this.domToHTML(this.doc.body);
22785         }
22786         
22787         //Roo.log(currentElement);
22788         var j;
22789         var allText = false;
22790         var nodeName = currentElement.nodeName;
22791         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22792         
22793         if  (nodeName == '#text') {
22794             
22795             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22796         }
22797         
22798         
22799         var ret = '';
22800         if (nodeName != 'BODY') {
22801              
22802             var i = 0;
22803             // Prints the node tagName, such as <A>, <IMG>, etc
22804             if (tagName) {
22805                 var attr = [];
22806                 for(i = 0; i < currentElement.attributes.length;i++) {
22807                     // quoting?
22808                     var aname = currentElement.attributes.item(i).name;
22809                     if (!currentElement.attributes.item(i).value.length) {
22810                         continue;
22811                     }
22812                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22813                 }
22814                 
22815                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22816             } 
22817             else {
22818                 
22819                 // eack
22820             }
22821         } else {
22822             tagName = false;
22823         }
22824         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22825             return ret;
22826         }
22827         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22828             nopadtext = true;
22829         }
22830         
22831         
22832         // Traverse the tree
22833         i = 0;
22834         var currentElementChild = currentElement.childNodes.item(i);
22835         var allText = true;
22836         var innerHTML  = '';
22837         lastnode = '';
22838         while (currentElementChild) {
22839             // Formatting code (indent the tree so it looks nice on the screen)
22840             var nopad = nopadtext;
22841             if (lastnode == 'SPAN') {
22842                 nopad  = true;
22843             }
22844             // text
22845             if  (currentElementChild.nodeName == '#text') {
22846                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22847                 toadd = nopadtext ? toadd : toadd.trim();
22848                 if (!nopad && toadd.length > 80) {
22849                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22850                 }
22851                 innerHTML  += toadd;
22852                 
22853                 i++;
22854                 currentElementChild = currentElement.childNodes.item(i);
22855                 lastNode = '';
22856                 continue;
22857             }
22858             allText = false;
22859             
22860             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22861                 
22862             // Recursively traverse the tree structure of the child node
22863             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22864             lastnode = currentElementChild.nodeName;
22865             i++;
22866             currentElementChild=currentElement.childNodes.item(i);
22867         }
22868         
22869         ret += innerHTML;
22870         
22871         if (!allText) {
22872                 // The remaining code is mostly for formatting the tree
22873             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22874         }
22875         
22876         
22877         if (tagName) {
22878             ret+= "</"+tagName+">";
22879         }
22880         return ret;
22881         
22882     },
22883         
22884     applyBlacklists : function()
22885     {
22886         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22887         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22888         
22889         this.white = [];
22890         this.black = [];
22891         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22892             if (b.indexOf(tag) > -1) {
22893                 return;
22894             }
22895             this.white.push(tag);
22896             
22897         }, this);
22898         
22899         Roo.each(w, function(tag) {
22900             if (b.indexOf(tag) > -1) {
22901                 return;
22902             }
22903             if (this.white.indexOf(tag) > -1) {
22904                 return;
22905             }
22906             this.white.push(tag);
22907             
22908         }, this);
22909         
22910         
22911         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22912             if (w.indexOf(tag) > -1) {
22913                 return;
22914             }
22915             this.black.push(tag);
22916             
22917         }, this);
22918         
22919         Roo.each(b, function(tag) {
22920             if (w.indexOf(tag) > -1) {
22921                 return;
22922             }
22923             if (this.black.indexOf(tag) > -1) {
22924                 return;
22925             }
22926             this.black.push(tag);
22927             
22928         }, this);
22929         
22930         
22931         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22932         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22933         
22934         this.cwhite = [];
22935         this.cblack = [];
22936         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22937             if (b.indexOf(tag) > -1) {
22938                 return;
22939             }
22940             this.cwhite.push(tag);
22941             
22942         }, this);
22943         
22944         Roo.each(w, function(tag) {
22945             if (b.indexOf(tag) > -1) {
22946                 return;
22947             }
22948             if (this.cwhite.indexOf(tag) > -1) {
22949                 return;
22950             }
22951             this.cwhite.push(tag);
22952             
22953         }, this);
22954         
22955         
22956         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22957             if (w.indexOf(tag) > -1) {
22958                 return;
22959             }
22960             this.cblack.push(tag);
22961             
22962         }, this);
22963         
22964         Roo.each(b, function(tag) {
22965             if (w.indexOf(tag) > -1) {
22966                 return;
22967             }
22968             if (this.cblack.indexOf(tag) > -1) {
22969                 return;
22970             }
22971             this.cblack.push(tag);
22972             
22973         }, this);
22974     },
22975     
22976     setStylesheets : function(stylesheets)
22977     {
22978         if(typeof(stylesheets) == 'string'){
22979             Roo.get(this.iframe.contentDocument.head).createChild({
22980                 tag : 'link',
22981                 rel : 'stylesheet',
22982                 type : 'text/css',
22983                 href : stylesheets
22984             });
22985             
22986             return;
22987         }
22988         var _this = this;
22989      
22990         Roo.each(stylesheets, function(s) {
22991             if(!s.length){
22992                 return;
22993             }
22994             
22995             Roo.get(_this.iframe.contentDocument.head).createChild({
22996                 tag : 'link',
22997                 rel : 'stylesheet',
22998                 type : 'text/css',
22999                 href : s
23000             });
23001         });
23002
23003         
23004     },
23005     
23006     removeStylesheets : function()
23007     {
23008         var _this = this;
23009         
23010         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23011             s.remove();
23012         });
23013     },
23014     
23015     setStyle : function(style)
23016     {
23017         Roo.get(this.iframe.contentDocument.head).createChild({
23018             tag : 'style',
23019             type : 'text/css',
23020             html : style
23021         });
23022
23023         return;
23024     }
23025     
23026     // hide stuff that is not compatible
23027     /**
23028      * @event blur
23029      * @hide
23030      */
23031     /**
23032      * @event change
23033      * @hide
23034      */
23035     /**
23036      * @event focus
23037      * @hide
23038      */
23039     /**
23040      * @event specialkey
23041      * @hide
23042      */
23043     /**
23044      * @cfg {String} fieldClass @hide
23045      */
23046     /**
23047      * @cfg {String} focusClass @hide
23048      */
23049     /**
23050      * @cfg {String} autoCreate @hide
23051      */
23052     /**
23053      * @cfg {String} inputType @hide
23054      */
23055     /**
23056      * @cfg {String} invalidClass @hide
23057      */
23058     /**
23059      * @cfg {String} invalidText @hide
23060      */
23061     /**
23062      * @cfg {String} msgFx @hide
23063      */
23064     /**
23065      * @cfg {String} validateOnBlur @hide
23066      */
23067 });
23068
23069 Roo.HtmlEditorCore.white = [
23070         'area', 'br', 'img', 'input', 'hr', 'wbr',
23071         
23072        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
23073        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
23074        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
23075        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
23076        'table',   'ul',         'xmp', 
23077        
23078        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
23079       'thead',   'tr', 
23080      
23081       'dir', 'menu', 'ol', 'ul', 'dl',
23082        
23083       'embed',  'object'
23084 ];
23085
23086
23087 Roo.HtmlEditorCore.black = [
23088     //    'embed',  'object', // enable - backend responsiblity to clean thiese
23089         'applet', // 
23090         'base',   'basefont', 'bgsound', 'blink',  'body', 
23091         'frame',  'frameset', 'head',    'html',   'ilayer', 
23092         'iframe', 'layer',  'link',     'meta',    'object',   
23093         'script', 'style' ,'title',  'xml' // clean later..
23094 ];
23095 Roo.HtmlEditorCore.clean = [
23096     'script', 'style', 'title', 'xml'
23097 ];
23098 Roo.HtmlEditorCore.remove = [
23099     'font'
23100 ];
23101 // attributes..
23102
23103 Roo.HtmlEditorCore.ablack = [
23104     'on'
23105 ];
23106     
23107 Roo.HtmlEditorCore.aclean = [ 
23108     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
23109 ];
23110
23111 // protocols..
23112 Roo.HtmlEditorCore.pwhite= [
23113         'http',  'https',  'mailto'
23114 ];
23115
23116 // white listed style attributes.
23117 Roo.HtmlEditorCore.cwhite= [
23118       //  'text-align', /// default is to allow most things..
23119       
23120          
23121 //        'font-size'//??
23122 ];
23123
23124 // black listed style attributes.
23125 Roo.HtmlEditorCore.cblack= [
23126       //  'font-size' -- this can be set by the project 
23127 ];
23128
23129
23130 Roo.HtmlEditorCore.swapCodes   =[ 
23131     [    8211, "--" ], 
23132     [    8212, "--" ], 
23133     [    8216,  "'" ],  
23134     [    8217, "'" ],  
23135     [    8220, '"' ],  
23136     [    8221, '"' ],  
23137     [    8226, "*" ],  
23138     [    8230, "..." ]
23139 ]; 
23140
23141     /*
23142  * - LGPL
23143  *
23144  * HtmlEditor
23145  * 
23146  */
23147
23148 /**
23149  * @class Roo.bootstrap.HtmlEditor
23150  * @extends Roo.bootstrap.TextArea
23151  * Bootstrap HtmlEditor class
23152
23153  * @constructor
23154  * Create a new HtmlEditor
23155  * @param {Object} config The config object
23156  */
23157
23158 Roo.bootstrap.HtmlEditor = function(config){
23159     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23160     if (!this.toolbars) {
23161         this.toolbars = [];
23162     }
23163     
23164     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23165     this.addEvents({
23166             /**
23167              * @event initialize
23168              * Fires when the editor is fully initialized (including the iframe)
23169              * @param {HtmlEditor} this
23170              */
23171             initialize: true,
23172             /**
23173              * @event activate
23174              * Fires when the editor is first receives the focus. Any insertion must wait
23175              * until after this event.
23176              * @param {HtmlEditor} this
23177              */
23178             activate: true,
23179              /**
23180              * @event beforesync
23181              * Fires before the textarea is updated with content from the editor iframe. Return false
23182              * to cancel the sync.
23183              * @param {HtmlEditor} this
23184              * @param {String} html
23185              */
23186             beforesync: true,
23187              /**
23188              * @event beforepush
23189              * Fires before the iframe editor is updated with content from the textarea. Return false
23190              * to cancel the push.
23191              * @param {HtmlEditor} this
23192              * @param {String} html
23193              */
23194             beforepush: true,
23195              /**
23196              * @event sync
23197              * Fires when the textarea is updated with content from the editor iframe.
23198              * @param {HtmlEditor} this
23199              * @param {String} html
23200              */
23201             sync: true,
23202              /**
23203              * @event push
23204              * Fires when the iframe editor is updated with content from the textarea.
23205              * @param {HtmlEditor} this
23206              * @param {String} html
23207              */
23208             push: true,
23209              /**
23210              * @event editmodechange
23211              * Fires when the editor switches edit modes
23212              * @param {HtmlEditor} this
23213              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23214              */
23215             editmodechange: true,
23216             /**
23217              * @event editorevent
23218              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23219              * @param {HtmlEditor} this
23220              */
23221             editorevent: true,
23222             /**
23223              * @event firstfocus
23224              * Fires when on first focus - needed by toolbars..
23225              * @param {HtmlEditor} this
23226              */
23227             firstfocus: true,
23228             /**
23229              * @event autosave
23230              * Auto save the htmlEditor value as a file into Events
23231              * @param {HtmlEditor} this
23232              */
23233             autosave: true,
23234             /**
23235              * @event savedpreview
23236              * preview the saved version of htmlEditor
23237              * @param {HtmlEditor} this
23238              */
23239             savedpreview: true
23240         });
23241 };
23242
23243
23244 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23245     
23246     
23247       /**
23248      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23249      */
23250     toolbars : false,
23251     
23252      /**
23253     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23254     */
23255     btns : [],
23256    
23257      /**
23258      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23259      *                        Roo.resizable.
23260      */
23261     resizable : false,
23262      /**
23263      * @cfg {Number} height (in pixels)
23264      */   
23265     height: 300,
23266    /**
23267      * @cfg {Number} width (in pixels)
23268      */   
23269     width: false,
23270     
23271     /**
23272      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23273      * 
23274      */
23275     stylesheets: false,
23276     
23277     // id of frame..
23278     frameId: false,
23279     
23280     // private properties
23281     validationEvent : false,
23282     deferHeight: true,
23283     initialized : false,
23284     activated : false,
23285     
23286     onFocus : Roo.emptyFn,
23287     iframePad:3,
23288     hideMode:'offsets',
23289     
23290     tbContainer : false,
23291     
23292     bodyCls : '',
23293     
23294     toolbarContainer :function() {
23295         return this.wrap.select('.x-html-editor-tb',true).first();
23296     },
23297
23298     /**
23299      * Protected method that will not generally be called directly. It
23300      * is called when the editor creates its toolbar. Override this method if you need to
23301      * add custom toolbar buttons.
23302      * @param {HtmlEditor} editor
23303      */
23304     createToolbar : function(){
23305         Roo.log('renewing');
23306         Roo.log("create toolbars");
23307         
23308         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23309         this.toolbars[0].render(this.toolbarContainer());
23310         
23311         return;
23312         
23313 //        if (!editor.toolbars || !editor.toolbars.length) {
23314 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23315 //        }
23316 //        
23317 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23318 //            editor.toolbars[i] = Roo.factory(
23319 //                    typeof(editor.toolbars[i]) == 'string' ?
23320 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23321 //                Roo.bootstrap.HtmlEditor);
23322 //            editor.toolbars[i].init(editor);
23323 //        }
23324     },
23325
23326      
23327     // private
23328     onRender : function(ct, position)
23329     {
23330        // Roo.log("Call onRender: " + this.xtype);
23331         var _t = this;
23332         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23333       
23334         this.wrap = this.inputEl().wrap({
23335             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23336         });
23337         
23338         this.editorcore.onRender(ct, position);
23339          
23340         if (this.resizable) {
23341             this.resizeEl = new Roo.Resizable(this.wrap, {
23342                 pinned : true,
23343                 wrap: true,
23344                 dynamic : true,
23345                 minHeight : this.height,
23346                 height: this.height,
23347                 handles : this.resizable,
23348                 width: this.width,
23349                 listeners : {
23350                     resize : function(r, w, h) {
23351                         _t.onResize(w,h); // -something
23352                     }
23353                 }
23354             });
23355             
23356         }
23357         this.createToolbar(this);
23358        
23359         
23360         if(!this.width && this.resizable){
23361             this.setSize(this.wrap.getSize());
23362         }
23363         if (this.resizeEl) {
23364             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23365             // should trigger onReize..
23366         }
23367         
23368     },
23369
23370     // private
23371     onResize : function(w, h)
23372     {
23373         Roo.log('resize: ' +w + ',' + h );
23374         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23375         var ew = false;
23376         var eh = false;
23377         
23378         if(this.inputEl() ){
23379             if(typeof w == 'number'){
23380                 var aw = w - this.wrap.getFrameWidth('lr');
23381                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23382                 ew = aw;
23383             }
23384             if(typeof h == 'number'){
23385                  var tbh = -11;  // fixme it needs to tool bar size!
23386                 for (var i =0; i < this.toolbars.length;i++) {
23387                     // fixme - ask toolbars for heights?
23388                     tbh += this.toolbars[i].el.getHeight();
23389                     //if (this.toolbars[i].footer) {
23390                     //    tbh += this.toolbars[i].footer.el.getHeight();
23391                     //}
23392                 }
23393               
23394                 
23395                 
23396                 
23397                 
23398                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23399                 ah -= 5; // knock a few pixes off for look..
23400                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23401                 var eh = ah;
23402             }
23403         }
23404         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23405         this.editorcore.onResize(ew,eh);
23406         
23407     },
23408
23409     /**
23410      * Toggles the editor between standard and source edit mode.
23411      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23412      */
23413     toggleSourceEdit : function(sourceEditMode)
23414     {
23415         this.editorcore.toggleSourceEdit(sourceEditMode);
23416         
23417         if(this.editorcore.sourceEditMode){
23418             Roo.log('editor - showing textarea');
23419             
23420 //            Roo.log('in');
23421 //            Roo.log(this.syncValue());
23422             this.syncValue();
23423             this.inputEl().removeClass(['hide', 'x-hidden']);
23424             this.inputEl().dom.removeAttribute('tabIndex');
23425             this.inputEl().focus();
23426         }else{
23427             Roo.log('editor - hiding textarea');
23428 //            Roo.log('out')
23429 //            Roo.log(this.pushValue()); 
23430             this.pushValue();
23431             
23432             this.inputEl().addClass(['hide', 'x-hidden']);
23433             this.inputEl().dom.setAttribute('tabIndex', -1);
23434             //this.deferFocus();
23435         }
23436          
23437         if(this.resizable){
23438             this.setSize(this.wrap.getSize());
23439         }
23440         
23441         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23442     },
23443  
23444     // private (for BoxComponent)
23445     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23446
23447     // private (for BoxComponent)
23448     getResizeEl : function(){
23449         return this.wrap;
23450     },
23451
23452     // private (for BoxComponent)
23453     getPositionEl : function(){
23454         return this.wrap;
23455     },
23456
23457     // private
23458     initEvents : function(){
23459         this.originalValue = this.getValue();
23460     },
23461
23462 //    /**
23463 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23464 //     * @method
23465 //     */
23466 //    markInvalid : Roo.emptyFn,
23467 //    /**
23468 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23469 //     * @method
23470 //     */
23471 //    clearInvalid : Roo.emptyFn,
23472
23473     setValue : function(v){
23474         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23475         this.editorcore.pushValue();
23476     },
23477
23478      
23479     // private
23480     deferFocus : function(){
23481         this.focus.defer(10, this);
23482     },
23483
23484     // doc'ed in Field
23485     focus : function(){
23486         this.editorcore.focus();
23487         
23488     },
23489       
23490
23491     // private
23492     onDestroy : function(){
23493         
23494         
23495         
23496         if(this.rendered){
23497             
23498             for (var i =0; i < this.toolbars.length;i++) {
23499                 // fixme - ask toolbars for heights?
23500                 this.toolbars[i].onDestroy();
23501             }
23502             
23503             this.wrap.dom.innerHTML = '';
23504             this.wrap.remove();
23505         }
23506     },
23507
23508     // private
23509     onFirstFocus : function(){
23510         //Roo.log("onFirstFocus");
23511         this.editorcore.onFirstFocus();
23512          for (var i =0; i < this.toolbars.length;i++) {
23513             this.toolbars[i].onFirstFocus();
23514         }
23515         
23516     },
23517     
23518     // private
23519     syncValue : function()
23520     {   
23521         this.editorcore.syncValue();
23522     },
23523     
23524     pushValue : function()
23525     {   
23526         this.editorcore.pushValue();
23527     }
23528      
23529     
23530     // hide stuff that is not compatible
23531     /**
23532      * @event blur
23533      * @hide
23534      */
23535     /**
23536      * @event change
23537      * @hide
23538      */
23539     /**
23540      * @event focus
23541      * @hide
23542      */
23543     /**
23544      * @event specialkey
23545      * @hide
23546      */
23547     /**
23548      * @cfg {String} fieldClass @hide
23549      */
23550     /**
23551      * @cfg {String} focusClass @hide
23552      */
23553     /**
23554      * @cfg {String} autoCreate @hide
23555      */
23556     /**
23557      * @cfg {String} inputType @hide
23558      */
23559     /**
23560      * @cfg {String} invalidClass @hide
23561      */
23562     /**
23563      * @cfg {String} invalidText @hide
23564      */
23565     /**
23566      * @cfg {String} msgFx @hide
23567      */
23568     /**
23569      * @cfg {String} validateOnBlur @hide
23570      */
23571 });
23572  
23573     
23574    
23575    
23576    
23577       
23578 Roo.namespace('Roo.bootstrap.htmleditor');
23579 /**
23580  * @class Roo.bootstrap.HtmlEditorToolbar1
23581  * Basic Toolbar
23582  * 
23583  * Usage:
23584  *
23585  new Roo.bootstrap.HtmlEditor({
23586     ....
23587     toolbars : [
23588         new Roo.bootstrap.HtmlEditorToolbar1({
23589             disable : { fonts: 1 , format: 1, ..., ... , ...],
23590             btns : [ .... ]
23591         })
23592     }
23593      
23594  * 
23595  * @cfg {Object} disable List of elements to disable..
23596  * @cfg {Array} btns List of additional buttons.
23597  * 
23598  * 
23599  * NEEDS Extra CSS? 
23600  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23601  */
23602  
23603 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23604 {
23605     
23606     Roo.apply(this, config);
23607     
23608     // default disabled, based on 'good practice'..
23609     this.disable = this.disable || {};
23610     Roo.applyIf(this.disable, {
23611         fontSize : true,
23612         colors : true,
23613         specialElements : true
23614     });
23615     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23616     
23617     this.editor = config.editor;
23618     this.editorcore = config.editor.editorcore;
23619     
23620     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23621     
23622     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23623     // dont call parent... till later.
23624 }
23625 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23626      
23627     bar : true,
23628     
23629     editor : false,
23630     editorcore : false,
23631     
23632     
23633     formats : [
23634         "p" ,  
23635         "h1","h2","h3","h4","h5","h6", 
23636         "pre", "code", 
23637         "abbr", "acronym", "address", "cite", "samp", "var",
23638         'div','span'
23639     ],
23640     
23641     onRender : function(ct, position)
23642     {
23643        // Roo.log("Call onRender: " + this.xtype);
23644         
23645        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23646        Roo.log(this.el);
23647        this.el.dom.style.marginBottom = '0';
23648        var _this = this;
23649        var editorcore = this.editorcore;
23650        var editor= this.editor;
23651        
23652        var children = [];
23653        var btn = function(id,cmd , toggle, handler, html){
23654        
23655             var  event = toggle ? 'toggle' : 'click';
23656        
23657             var a = {
23658                 size : 'sm',
23659                 xtype: 'Button',
23660                 xns: Roo.bootstrap,
23661                 glyphicon : id,
23662                 cmd : id || cmd,
23663                 enableToggle:toggle !== false,
23664                 html : html || '',
23665                 pressed : toggle ? false : null,
23666                 listeners : {}
23667             };
23668             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23669                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23670             };
23671             children.push(a);
23672             return a;
23673        }
23674        
23675     //    var cb_box = function...
23676         
23677         var style = {
23678                 xtype: 'Button',
23679                 size : 'sm',
23680                 xns: Roo.bootstrap,
23681                 glyphicon : 'font',
23682                 //html : 'submit'
23683                 menu : {
23684                     xtype: 'Menu',
23685                     xns: Roo.bootstrap,
23686                     items:  []
23687                 }
23688         };
23689         Roo.each(this.formats, function(f) {
23690             style.menu.items.push({
23691                 xtype :'MenuItem',
23692                 xns: Roo.bootstrap,
23693                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23694                 tagname : f,
23695                 listeners : {
23696                     click : function()
23697                     {
23698                         editorcore.insertTag(this.tagname);
23699                         editor.focus();
23700                     }
23701                 }
23702                 
23703             });
23704         });
23705         children.push(style);   
23706         
23707         btn('bold',false,true);
23708         btn('italic',false,true);
23709         btn('align-left', 'justifyleft',true);
23710         btn('align-center', 'justifycenter',true);
23711         btn('align-right' , 'justifyright',true);
23712         btn('link', false, false, function(btn) {
23713             //Roo.log("create link?");
23714             var url = prompt(this.createLinkText, this.defaultLinkValue);
23715             if(url && url != 'http:/'+'/'){
23716                 this.editorcore.relayCmd('createlink', url);
23717             }
23718         }),
23719         btn('list','insertunorderedlist',true);
23720         btn('pencil', false,true, function(btn){
23721                 Roo.log(this);
23722                 this.toggleSourceEdit(btn.pressed);
23723         });
23724         
23725         if (this.editor.btns.length > 0) {
23726             for (var i = 0; i<this.editor.btns.length; i++) {
23727                 children.push(this.editor.btns[i]);
23728             }
23729         }
23730         
23731         /*
23732         var cog = {
23733                 xtype: 'Button',
23734                 size : 'sm',
23735                 xns: Roo.bootstrap,
23736                 glyphicon : 'cog',
23737                 //html : 'submit'
23738                 menu : {
23739                     xtype: 'Menu',
23740                     xns: Roo.bootstrap,
23741                     items:  []
23742                 }
23743         };
23744         
23745         cog.menu.items.push({
23746             xtype :'MenuItem',
23747             xns: Roo.bootstrap,
23748             html : Clean styles,
23749             tagname : f,
23750             listeners : {
23751                 click : function()
23752                 {
23753                     editorcore.insertTag(this.tagname);
23754                     editor.focus();
23755                 }
23756             }
23757             
23758         });
23759        */
23760         
23761          
23762        this.xtype = 'NavSimplebar';
23763         
23764         for(var i=0;i< children.length;i++) {
23765             
23766             this.buttons.add(this.addxtypeChild(children[i]));
23767             
23768         }
23769         
23770         editor.on('editorevent', this.updateToolbar, this);
23771     },
23772     onBtnClick : function(id)
23773     {
23774        this.editorcore.relayCmd(id);
23775        this.editorcore.focus();
23776     },
23777     
23778     /**
23779      * Protected method that will not generally be called directly. It triggers
23780      * a toolbar update by reading the markup state of the current selection in the editor.
23781      */
23782     updateToolbar: function(){
23783
23784         if(!this.editorcore.activated){
23785             this.editor.onFirstFocus(); // is this neeed?
23786             return;
23787         }
23788
23789         var btns = this.buttons; 
23790         var doc = this.editorcore.doc;
23791         btns.get('bold').setActive(doc.queryCommandState('bold'));
23792         btns.get('italic').setActive(doc.queryCommandState('italic'));
23793         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23794         
23795         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23796         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23797         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23798         
23799         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23800         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23801          /*
23802         
23803         var ans = this.editorcore.getAllAncestors();
23804         if (this.formatCombo) {
23805             
23806             
23807             var store = this.formatCombo.store;
23808             this.formatCombo.setValue("");
23809             for (var i =0; i < ans.length;i++) {
23810                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23811                     // select it..
23812                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23813                     break;
23814                 }
23815             }
23816         }
23817         
23818         
23819         
23820         // hides menus... - so this cant be on a menu...
23821         Roo.bootstrap.MenuMgr.hideAll();
23822         */
23823         Roo.bootstrap.MenuMgr.hideAll();
23824         //this.editorsyncValue();
23825     },
23826     onFirstFocus: function() {
23827         this.buttons.each(function(item){
23828            item.enable();
23829         });
23830     },
23831     toggleSourceEdit : function(sourceEditMode){
23832         
23833           
23834         if(sourceEditMode){
23835             Roo.log("disabling buttons");
23836            this.buttons.each( function(item){
23837                 if(item.cmd != 'pencil'){
23838                     item.disable();
23839                 }
23840             });
23841           
23842         }else{
23843             Roo.log("enabling buttons");
23844             if(this.editorcore.initialized){
23845                 this.buttons.each( function(item){
23846                     item.enable();
23847                 });
23848             }
23849             
23850         }
23851         Roo.log("calling toggole on editor");
23852         // tell the editor that it's been pressed..
23853         this.editor.toggleSourceEdit(sourceEditMode);
23854        
23855     }
23856 });
23857
23858
23859
23860
23861
23862 /**
23863  * @class Roo.bootstrap.Table.AbstractSelectionModel
23864  * @extends Roo.util.Observable
23865  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23866  * implemented by descendant classes.  This class should not be directly instantiated.
23867  * @constructor
23868  */
23869 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23870     this.locked = false;
23871     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23872 };
23873
23874
23875 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23876     /** @ignore Called by the grid automatically. Do not call directly. */
23877     init : function(grid){
23878         this.grid = grid;
23879         this.initEvents();
23880     },
23881
23882     /**
23883      * Locks the selections.
23884      */
23885     lock : function(){
23886         this.locked = true;
23887     },
23888
23889     /**
23890      * Unlocks the selections.
23891      */
23892     unlock : function(){
23893         this.locked = false;
23894     },
23895
23896     /**
23897      * Returns true if the selections are locked.
23898      * @return {Boolean}
23899      */
23900     isLocked : function(){
23901         return this.locked;
23902     }
23903 });
23904 /**
23905  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23906  * @class Roo.bootstrap.Table.RowSelectionModel
23907  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23908  * It supports multiple selections and keyboard selection/navigation. 
23909  * @constructor
23910  * @param {Object} config
23911  */
23912
23913 Roo.bootstrap.Table.RowSelectionModel = function(config){
23914     Roo.apply(this, config);
23915     this.selections = new Roo.util.MixedCollection(false, function(o){
23916         return o.id;
23917     });
23918
23919     this.last = false;
23920     this.lastActive = false;
23921
23922     this.addEvents({
23923         /**
23924              * @event selectionchange
23925              * Fires when the selection changes
23926              * @param {SelectionModel} this
23927              */
23928             "selectionchange" : true,
23929         /**
23930              * @event afterselectionchange
23931              * Fires after the selection changes (eg. by key press or clicking)
23932              * @param {SelectionModel} this
23933              */
23934             "afterselectionchange" : true,
23935         /**
23936              * @event beforerowselect
23937              * Fires when a row is selected being selected, return false to cancel.
23938              * @param {SelectionModel} this
23939              * @param {Number} rowIndex The selected index
23940              * @param {Boolean} keepExisting False if other selections will be cleared
23941              */
23942             "beforerowselect" : true,
23943         /**
23944              * @event rowselect
23945              * Fires when a row is selected.
23946              * @param {SelectionModel} this
23947              * @param {Number} rowIndex The selected index
23948              * @param {Roo.data.Record} r The record
23949              */
23950             "rowselect" : true,
23951         /**
23952              * @event rowdeselect
23953              * Fires when a row is deselected.
23954              * @param {SelectionModel} this
23955              * @param {Number} rowIndex The selected index
23956              */
23957         "rowdeselect" : true
23958     });
23959     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23960     this.locked = false;
23961  };
23962
23963 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
23964     /**
23965      * @cfg {Boolean} singleSelect
23966      * True to allow selection of only one row at a time (defaults to false)
23967      */
23968     singleSelect : false,
23969
23970     // private
23971     initEvents : function()
23972     {
23973
23974         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23975         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
23976         //}else{ // allow click to work like normal
23977          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
23978         //}
23979         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23980         this.grid.on("rowclick", this.handleMouseDown, this);
23981         
23982         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23983             "up" : function(e){
23984                 if(!e.shiftKey){
23985                     this.selectPrevious(e.shiftKey);
23986                 }else if(this.last !== false && this.lastActive !== false){
23987                     var last = this.last;
23988                     this.selectRange(this.last,  this.lastActive-1);
23989                     this.grid.getView().focusRow(this.lastActive);
23990                     if(last !== false){
23991                         this.last = last;
23992                     }
23993                 }else{
23994                     this.selectFirstRow();
23995                 }
23996                 this.fireEvent("afterselectionchange", this);
23997             },
23998             "down" : function(e){
23999                 if(!e.shiftKey){
24000                     this.selectNext(e.shiftKey);
24001                 }else if(this.last !== false && this.lastActive !== false){
24002                     var last = this.last;
24003                     this.selectRange(this.last,  this.lastActive+1);
24004                     this.grid.getView().focusRow(this.lastActive);
24005                     if(last !== false){
24006                         this.last = last;
24007                     }
24008                 }else{
24009                     this.selectFirstRow();
24010                 }
24011                 this.fireEvent("afterselectionchange", this);
24012             },
24013             scope: this
24014         });
24015         this.grid.store.on('load', function(){
24016             this.selections.clear();
24017         },this);
24018         /*
24019         var view = this.grid.view;
24020         view.on("refresh", this.onRefresh, this);
24021         view.on("rowupdated", this.onRowUpdated, this);
24022         view.on("rowremoved", this.onRemove, this);
24023         */
24024     },
24025
24026     // private
24027     onRefresh : function()
24028     {
24029         var ds = this.grid.store, i, v = this.grid.view;
24030         var s = this.selections;
24031         s.each(function(r){
24032             if((i = ds.indexOfId(r.id)) != -1){
24033                 v.onRowSelect(i);
24034             }else{
24035                 s.remove(r);
24036             }
24037         });
24038     },
24039
24040     // private
24041     onRemove : function(v, index, r){
24042         this.selections.remove(r);
24043     },
24044
24045     // private
24046     onRowUpdated : function(v, index, r){
24047         if(this.isSelected(r)){
24048             v.onRowSelect(index);
24049         }
24050     },
24051
24052     /**
24053      * Select records.
24054      * @param {Array} records The records to select
24055      * @param {Boolean} keepExisting (optional) True to keep existing selections
24056      */
24057     selectRecords : function(records, keepExisting)
24058     {
24059         if(!keepExisting){
24060             this.clearSelections();
24061         }
24062             var ds = this.grid.store;
24063         for(var i = 0, len = records.length; i < len; i++){
24064             this.selectRow(ds.indexOf(records[i]), true);
24065         }
24066     },
24067
24068     /**
24069      * Gets the number of selected rows.
24070      * @return {Number}
24071      */
24072     getCount : function(){
24073         return this.selections.length;
24074     },
24075
24076     /**
24077      * Selects the first row in the grid.
24078      */
24079     selectFirstRow : function(){
24080         this.selectRow(0);
24081     },
24082
24083     /**
24084      * Select the last row.
24085      * @param {Boolean} keepExisting (optional) True to keep existing selections
24086      */
24087     selectLastRow : function(keepExisting){
24088         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24089         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24090     },
24091
24092     /**
24093      * Selects the row immediately following the last selected row.
24094      * @param {Boolean} keepExisting (optional) True to keep existing selections
24095      */
24096     selectNext : function(keepExisting)
24097     {
24098             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24099             this.selectRow(this.last+1, keepExisting);
24100             this.grid.getView().focusRow(this.last);
24101         }
24102     },
24103
24104     /**
24105      * Selects the row that precedes the last selected row.
24106      * @param {Boolean} keepExisting (optional) True to keep existing selections
24107      */
24108     selectPrevious : function(keepExisting){
24109         if(this.last){
24110             this.selectRow(this.last-1, keepExisting);
24111             this.grid.getView().focusRow(this.last);
24112         }
24113     },
24114
24115     /**
24116      * Returns the selected records
24117      * @return {Array} Array of selected records
24118      */
24119     getSelections : function(){
24120         return [].concat(this.selections.items);
24121     },
24122
24123     /**
24124      * Returns the first selected record.
24125      * @return {Record}
24126      */
24127     getSelected : function(){
24128         return this.selections.itemAt(0);
24129     },
24130
24131
24132     /**
24133      * Clears all selections.
24134      */
24135     clearSelections : function(fast)
24136     {
24137         if(this.locked) {
24138             return;
24139         }
24140         if(fast !== true){
24141                 var ds = this.grid.store;
24142             var s = this.selections;
24143             s.each(function(r){
24144                 this.deselectRow(ds.indexOfId(r.id));
24145             }, this);
24146             s.clear();
24147         }else{
24148             this.selections.clear();
24149         }
24150         this.last = false;
24151     },
24152
24153
24154     /**
24155      * Selects all rows.
24156      */
24157     selectAll : function(){
24158         if(this.locked) {
24159             return;
24160         }
24161         this.selections.clear();
24162         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24163             this.selectRow(i, true);
24164         }
24165     },
24166
24167     /**
24168      * Returns True if there is a selection.
24169      * @return {Boolean}
24170      */
24171     hasSelection : function(){
24172         return this.selections.length > 0;
24173     },
24174
24175     /**
24176      * Returns True if the specified row is selected.
24177      * @param {Number/Record} record The record or index of the record to check
24178      * @return {Boolean}
24179      */
24180     isSelected : function(index){
24181             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24182         return (r && this.selections.key(r.id) ? true : false);
24183     },
24184
24185     /**
24186      * Returns True if the specified record id is selected.
24187      * @param {String} id The id of record to check
24188      * @return {Boolean}
24189      */
24190     isIdSelected : function(id){
24191         return (this.selections.key(id) ? true : false);
24192     },
24193
24194
24195     // private
24196     handleMouseDBClick : function(e, t){
24197         
24198     },
24199     // private
24200     handleMouseDown : function(e, t)
24201     {
24202             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24203         if(this.isLocked() || rowIndex < 0 ){
24204             return;
24205         };
24206         if(e.shiftKey && this.last !== false){
24207             var last = this.last;
24208             this.selectRange(last, rowIndex, e.ctrlKey);
24209             this.last = last; // reset the last
24210             t.focus();
24211     
24212         }else{
24213             var isSelected = this.isSelected(rowIndex);
24214             //Roo.log("select row:" + rowIndex);
24215             if(isSelected){
24216                 this.deselectRow(rowIndex);
24217             } else {
24218                         this.selectRow(rowIndex, true);
24219             }
24220     
24221             /*
24222                 if(e.button !== 0 && isSelected){
24223                 alert('rowIndex 2: ' + rowIndex);
24224                     view.focusRow(rowIndex);
24225                 }else if(e.ctrlKey && isSelected){
24226                     this.deselectRow(rowIndex);
24227                 }else if(!isSelected){
24228                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24229                     view.focusRow(rowIndex);
24230                 }
24231             */
24232         }
24233         this.fireEvent("afterselectionchange", this);
24234     },
24235     // private
24236     handleDragableRowClick :  function(grid, rowIndex, e) 
24237     {
24238         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24239             this.selectRow(rowIndex, false);
24240             grid.view.focusRow(rowIndex);
24241              this.fireEvent("afterselectionchange", this);
24242         }
24243     },
24244     
24245     /**
24246      * Selects multiple rows.
24247      * @param {Array} rows Array of the indexes of the row to select
24248      * @param {Boolean} keepExisting (optional) True to keep existing selections
24249      */
24250     selectRows : function(rows, keepExisting){
24251         if(!keepExisting){
24252             this.clearSelections();
24253         }
24254         for(var i = 0, len = rows.length; i < len; i++){
24255             this.selectRow(rows[i], true);
24256         }
24257     },
24258
24259     /**
24260      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24261      * @param {Number} startRow The index of the first row in the range
24262      * @param {Number} endRow The index of the last row in the range
24263      * @param {Boolean} keepExisting (optional) True to retain existing selections
24264      */
24265     selectRange : function(startRow, endRow, keepExisting){
24266         if(this.locked) {
24267             return;
24268         }
24269         if(!keepExisting){
24270             this.clearSelections();
24271         }
24272         if(startRow <= endRow){
24273             for(var i = startRow; i <= endRow; i++){
24274                 this.selectRow(i, true);
24275             }
24276         }else{
24277             for(var i = startRow; i >= endRow; i--){
24278                 this.selectRow(i, true);
24279             }
24280         }
24281     },
24282
24283     /**
24284      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24285      * @param {Number} startRow The index of the first row in the range
24286      * @param {Number} endRow The index of the last row in the range
24287      */
24288     deselectRange : function(startRow, endRow, preventViewNotify){
24289         if(this.locked) {
24290             return;
24291         }
24292         for(var i = startRow; i <= endRow; i++){
24293             this.deselectRow(i, preventViewNotify);
24294         }
24295     },
24296
24297     /**
24298      * Selects a row.
24299      * @param {Number} row The index of the row to select
24300      * @param {Boolean} keepExisting (optional) True to keep existing selections
24301      */
24302     selectRow : function(index, keepExisting, preventViewNotify)
24303     {
24304             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24305             return;
24306         }
24307         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24308             if(!keepExisting || this.singleSelect){
24309                 this.clearSelections();
24310             }
24311             
24312             var r = this.grid.store.getAt(index);
24313             //console.log('selectRow - record id :' + r.id);
24314             
24315             this.selections.add(r);
24316             this.last = this.lastActive = index;
24317             if(!preventViewNotify){
24318                 var proxy = new Roo.Element(
24319                                 this.grid.getRowDom(index)
24320                 );
24321                 proxy.addClass('bg-info info');
24322             }
24323             this.fireEvent("rowselect", this, index, r);
24324             this.fireEvent("selectionchange", this);
24325         }
24326     },
24327
24328     /**
24329      * Deselects a row.
24330      * @param {Number} row The index of the row to deselect
24331      */
24332     deselectRow : function(index, preventViewNotify)
24333     {
24334         if(this.locked) {
24335             return;
24336         }
24337         if(this.last == index){
24338             this.last = false;
24339         }
24340         if(this.lastActive == index){
24341             this.lastActive = false;
24342         }
24343         
24344         var r = this.grid.store.getAt(index);
24345         if (!r) {
24346             return;
24347         }
24348         
24349         this.selections.remove(r);
24350         //.console.log('deselectRow - record id :' + r.id);
24351         if(!preventViewNotify){
24352         
24353             var proxy = new Roo.Element(
24354                 this.grid.getRowDom(index)
24355             );
24356             proxy.removeClass('bg-info info');
24357         }
24358         this.fireEvent("rowdeselect", this, index);
24359         this.fireEvent("selectionchange", this);
24360     },
24361
24362     // private
24363     restoreLast : function(){
24364         if(this._last){
24365             this.last = this._last;
24366         }
24367     },
24368
24369     // private
24370     acceptsNav : function(row, col, cm){
24371         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24372     },
24373
24374     // private
24375     onEditorKey : function(field, e){
24376         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24377         if(k == e.TAB){
24378             e.stopEvent();
24379             ed.completeEdit();
24380             if(e.shiftKey){
24381                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24382             }else{
24383                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24384             }
24385         }else if(k == e.ENTER && !e.ctrlKey){
24386             e.stopEvent();
24387             ed.completeEdit();
24388             if(e.shiftKey){
24389                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24390             }else{
24391                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24392             }
24393         }else if(k == e.ESC){
24394             ed.cancelEdit();
24395         }
24396         if(newCell){
24397             g.startEditing(newCell[0], newCell[1]);
24398         }
24399     }
24400 });
24401 /*
24402  * Based on:
24403  * Ext JS Library 1.1.1
24404  * Copyright(c) 2006-2007, Ext JS, LLC.
24405  *
24406  * Originally Released Under LGPL - original licence link has changed is not relivant.
24407  *
24408  * Fork - LGPL
24409  * <script type="text/javascript">
24410  */
24411  
24412 /**
24413  * @class Roo.bootstrap.PagingToolbar
24414  * @extends Roo.bootstrap.NavSimplebar
24415  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24416  * @constructor
24417  * Create a new PagingToolbar
24418  * @param {Object} config The config object
24419  * @param {Roo.data.Store} store
24420  */
24421 Roo.bootstrap.PagingToolbar = function(config)
24422 {
24423     // old args format still supported... - xtype is prefered..
24424         // created from xtype...
24425     
24426     this.ds = config.dataSource;
24427     
24428     if (config.store && !this.ds) {
24429         this.store= Roo.factory(config.store, Roo.data);
24430         this.ds = this.store;
24431         this.ds.xmodule = this.xmodule || false;
24432     }
24433     
24434     this.toolbarItems = [];
24435     if (config.items) {
24436         this.toolbarItems = config.items;
24437     }
24438     
24439     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24440     
24441     this.cursor = 0;
24442     
24443     if (this.ds) { 
24444         this.bind(this.ds);
24445     }
24446     
24447     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24448     
24449 };
24450
24451 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24452     /**
24453      * @cfg {Roo.data.Store} dataSource
24454      * The underlying data store providing the paged data
24455      */
24456     /**
24457      * @cfg {String/HTMLElement/Element} container
24458      * container The id or element that will contain the toolbar
24459      */
24460     /**
24461      * @cfg {Boolean} displayInfo
24462      * True to display the displayMsg (defaults to false)
24463      */
24464     /**
24465      * @cfg {Number} pageSize
24466      * The number of records to display per page (defaults to 20)
24467      */
24468     pageSize: 20,
24469     /**
24470      * @cfg {String} displayMsg
24471      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24472      */
24473     displayMsg : 'Displaying {0} - {1} of {2}',
24474     /**
24475      * @cfg {String} emptyMsg
24476      * The message to display when no records are found (defaults to "No data to display")
24477      */
24478     emptyMsg : 'No data to display',
24479     /**
24480      * Customizable piece of the default paging text (defaults to "Page")
24481      * @type String
24482      */
24483     beforePageText : "Page",
24484     /**
24485      * Customizable piece of the default paging text (defaults to "of %0")
24486      * @type String
24487      */
24488     afterPageText : "of {0}",
24489     /**
24490      * Customizable piece of the default paging text (defaults to "First Page")
24491      * @type String
24492      */
24493     firstText : "First Page",
24494     /**
24495      * Customizable piece of the default paging text (defaults to "Previous Page")
24496      * @type String
24497      */
24498     prevText : "Previous Page",
24499     /**
24500      * Customizable piece of the default paging text (defaults to "Next Page")
24501      * @type String
24502      */
24503     nextText : "Next Page",
24504     /**
24505      * Customizable piece of the default paging text (defaults to "Last Page")
24506      * @type String
24507      */
24508     lastText : "Last Page",
24509     /**
24510      * Customizable piece of the default paging text (defaults to "Refresh")
24511      * @type String
24512      */
24513     refreshText : "Refresh",
24514
24515     buttons : false,
24516     // private
24517     onRender : function(ct, position) 
24518     {
24519         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24520         this.navgroup.parentId = this.id;
24521         this.navgroup.onRender(this.el, null);
24522         // add the buttons to the navgroup
24523         
24524         if(this.displayInfo){
24525             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24526             this.displayEl = this.el.select('.x-paging-info', true).first();
24527 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24528 //            this.displayEl = navel.el.select('span',true).first();
24529         }
24530         
24531         var _this = this;
24532         
24533         if(this.buttons){
24534             Roo.each(_this.buttons, function(e){ // this might need to use render????
24535                Roo.factory(e).render(_this.el);
24536             });
24537         }
24538             
24539         Roo.each(_this.toolbarItems, function(e) {
24540             _this.navgroup.addItem(e);
24541         });
24542         
24543         
24544         this.first = this.navgroup.addItem({
24545             tooltip: this.firstText,
24546             cls: "prev",
24547             icon : 'fa fa-backward',
24548             disabled: true,
24549             preventDefault: true,
24550             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24551         });
24552         
24553         this.prev =  this.navgroup.addItem({
24554             tooltip: this.prevText,
24555             cls: "prev",
24556             icon : 'fa fa-step-backward',
24557             disabled: true,
24558             preventDefault: true,
24559             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24560         });
24561     //this.addSeparator();
24562         
24563         
24564         var field = this.navgroup.addItem( {
24565             tagtype : 'span',
24566             cls : 'x-paging-position',
24567             
24568             html : this.beforePageText  +
24569                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24570                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24571          } ); //?? escaped?
24572         
24573         this.field = field.el.select('input', true).first();
24574         this.field.on("keydown", this.onPagingKeydown, this);
24575         this.field.on("focus", function(){this.dom.select();});
24576     
24577     
24578         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24579         //this.field.setHeight(18);
24580         //this.addSeparator();
24581         this.next = this.navgroup.addItem({
24582             tooltip: this.nextText,
24583             cls: "next",
24584             html : ' <i class="fa fa-step-forward">',
24585             disabled: true,
24586             preventDefault: true,
24587             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24588         });
24589         this.last = this.navgroup.addItem({
24590             tooltip: this.lastText,
24591             icon : 'fa fa-forward',
24592             cls: "next",
24593             disabled: true,
24594             preventDefault: true,
24595             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24596         });
24597     //this.addSeparator();
24598         this.loading = this.navgroup.addItem({
24599             tooltip: this.refreshText,
24600             icon: 'fa fa-refresh',
24601             preventDefault: true,
24602             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24603         });
24604         
24605     },
24606
24607     // private
24608     updateInfo : function(){
24609         if(this.displayEl){
24610             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24611             var msg = count == 0 ?
24612                 this.emptyMsg :
24613                 String.format(
24614                     this.displayMsg,
24615                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24616                 );
24617             this.displayEl.update(msg);
24618         }
24619     },
24620
24621     // private
24622     onLoad : function(ds, r, o)
24623     {
24624         this.cursor = o.params.start ? o.params.start : 0;
24625         
24626         var d = this.getPageData(),
24627             ap = d.activePage,
24628             ps = d.pages;
24629         
24630         
24631         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24632         this.field.dom.value = ap;
24633         this.first.setDisabled(ap == 1);
24634         this.prev.setDisabled(ap == 1);
24635         this.next.setDisabled(ap == ps);
24636         this.last.setDisabled(ap == ps);
24637         this.loading.enable();
24638         this.updateInfo();
24639     },
24640
24641     // private
24642     getPageData : function(){
24643         var total = this.ds.getTotalCount();
24644         return {
24645             total : total,
24646             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24647             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24648         };
24649     },
24650
24651     // private
24652     onLoadError : function(){
24653         this.loading.enable();
24654     },
24655
24656     // private
24657     onPagingKeydown : function(e){
24658         var k = e.getKey();
24659         var d = this.getPageData();
24660         if(k == e.RETURN){
24661             var v = this.field.dom.value, pageNum;
24662             if(!v || isNaN(pageNum = parseInt(v, 10))){
24663                 this.field.dom.value = d.activePage;
24664                 return;
24665             }
24666             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24667             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24668             e.stopEvent();
24669         }
24670         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))
24671         {
24672           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24673           this.field.dom.value = pageNum;
24674           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24675           e.stopEvent();
24676         }
24677         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24678         {
24679           var v = this.field.dom.value, pageNum; 
24680           var increment = (e.shiftKey) ? 10 : 1;
24681           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24682                 increment *= -1;
24683           }
24684           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24685             this.field.dom.value = d.activePage;
24686             return;
24687           }
24688           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24689           {
24690             this.field.dom.value = parseInt(v, 10) + increment;
24691             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24692             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24693           }
24694           e.stopEvent();
24695         }
24696     },
24697
24698     // private
24699     beforeLoad : function(){
24700         if(this.loading){
24701             this.loading.disable();
24702         }
24703     },
24704
24705     // private
24706     onClick : function(which){
24707         
24708         var ds = this.ds;
24709         if (!ds) {
24710             return;
24711         }
24712         
24713         switch(which){
24714             case "first":
24715                 ds.load({params:{start: 0, limit: this.pageSize}});
24716             break;
24717             case "prev":
24718                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24719             break;
24720             case "next":
24721                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24722             break;
24723             case "last":
24724                 var total = ds.getTotalCount();
24725                 var extra = total % this.pageSize;
24726                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24727                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24728             break;
24729             case "refresh":
24730                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24731             break;
24732         }
24733     },
24734
24735     /**
24736      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24737      * @param {Roo.data.Store} store The data store to unbind
24738      */
24739     unbind : function(ds){
24740         ds.un("beforeload", this.beforeLoad, this);
24741         ds.un("load", this.onLoad, this);
24742         ds.un("loadexception", this.onLoadError, this);
24743         ds.un("remove", this.updateInfo, this);
24744         ds.un("add", this.updateInfo, this);
24745         this.ds = undefined;
24746     },
24747
24748     /**
24749      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24750      * @param {Roo.data.Store} store The data store to bind
24751      */
24752     bind : function(ds){
24753         ds.on("beforeload", this.beforeLoad, this);
24754         ds.on("load", this.onLoad, this);
24755         ds.on("loadexception", this.onLoadError, this);
24756         ds.on("remove", this.updateInfo, this);
24757         ds.on("add", this.updateInfo, this);
24758         this.ds = ds;
24759     }
24760 });/*
24761  * - LGPL
24762  *
24763  * element
24764  * 
24765  */
24766
24767 /**
24768  * @class Roo.bootstrap.MessageBar
24769  * @extends Roo.bootstrap.Component
24770  * Bootstrap MessageBar class
24771  * @cfg {String} html contents of the MessageBar
24772  * @cfg {String} weight (info | success | warning | danger) default info
24773  * @cfg {String} beforeClass insert the bar before the given class
24774  * @cfg {Boolean} closable (true | false) default false
24775  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24776  * 
24777  * @constructor
24778  * Create a new Element
24779  * @param {Object} config The config object
24780  */
24781
24782 Roo.bootstrap.MessageBar = function(config){
24783     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24784 };
24785
24786 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24787     
24788     html: '',
24789     weight: 'info',
24790     closable: false,
24791     fixed: false,
24792     beforeClass: 'bootstrap-sticky-wrap',
24793     
24794     getAutoCreate : function(){
24795         
24796         var cfg = {
24797             tag: 'div',
24798             cls: 'alert alert-dismissable alert-' + this.weight,
24799             cn: [
24800                 {
24801                     tag: 'span',
24802                     cls: 'message',
24803                     html: this.html || ''
24804                 }
24805             ]
24806         };
24807         
24808         if(this.fixed){
24809             cfg.cls += ' alert-messages-fixed';
24810         }
24811         
24812         if(this.closable){
24813             cfg.cn.push({
24814                 tag: 'button',
24815                 cls: 'close',
24816                 html: 'x'
24817             });
24818         }
24819         
24820         return cfg;
24821     },
24822     
24823     onRender : function(ct, position)
24824     {
24825         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24826         
24827         if(!this.el){
24828             var cfg = Roo.apply({},  this.getAutoCreate());
24829             cfg.id = Roo.id();
24830             
24831             if (this.cls) {
24832                 cfg.cls += ' ' + this.cls;
24833             }
24834             if (this.style) {
24835                 cfg.style = this.style;
24836             }
24837             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24838             
24839             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24840         }
24841         
24842         this.el.select('>button.close').on('click', this.hide, this);
24843         
24844     },
24845     
24846     show : function()
24847     {
24848         if (!this.rendered) {
24849             this.render();
24850         }
24851         
24852         this.el.show();
24853         
24854         this.fireEvent('show', this);
24855         
24856     },
24857     
24858     hide : function()
24859     {
24860         if (!this.rendered) {
24861             this.render();
24862         }
24863         
24864         this.el.hide();
24865         
24866         this.fireEvent('hide', this);
24867     },
24868     
24869     update : function()
24870     {
24871 //        var e = this.el.dom.firstChild;
24872 //        
24873 //        if(this.closable){
24874 //            e = e.nextSibling;
24875 //        }
24876 //        
24877 //        e.data = this.html || '';
24878
24879         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24880     }
24881    
24882 });
24883
24884  
24885
24886      /*
24887  * - LGPL
24888  *
24889  * Graph
24890  * 
24891  */
24892
24893
24894 /**
24895  * @class Roo.bootstrap.Graph
24896  * @extends Roo.bootstrap.Component
24897  * Bootstrap Graph class
24898 > Prameters
24899  -sm {number} sm 4
24900  -md {number} md 5
24901  @cfg {String} graphtype  bar | vbar | pie
24902  @cfg {number} g_x coodinator | centre x (pie)
24903  @cfg {number} g_y coodinator | centre y (pie)
24904  @cfg {number} g_r radius (pie)
24905  @cfg {number} g_height height of the chart (respected by all elements in the set)
24906  @cfg {number} g_width width of the chart (respected by all elements in the set)
24907  @cfg {Object} title The title of the chart
24908     
24909  -{Array}  values
24910  -opts (object) options for the chart 
24911      o {
24912      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24913      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24914      o vgutter (number)
24915      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.
24916      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24917      o to
24918      o stretch (boolean)
24919      o }
24920  -opts (object) options for the pie
24921      o{
24922      o cut
24923      o startAngle (number)
24924      o endAngle (number)
24925      } 
24926  *
24927  * @constructor
24928  * Create a new Input
24929  * @param {Object} config The config object
24930  */
24931
24932 Roo.bootstrap.Graph = function(config){
24933     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24934     
24935     this.addEvents({
24936         // img events
24937         /**
24938          * @event click
24939          * The img click event for the img.
24940          * @param {Roo.EventObject} e
24941          */
24942         "click" : true
24943     });
24944 };
24945
24946 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24947     
24948     sm: 4,
24949     md: 5,
24950     graphtype: 'bar',
24951     g_height: 250,
24952     g_width: 400,
24953     g_x: 50,
24954     g_y: 50,
24955     g_r: 30,
24956     opts:{
24957         //g_colors: this.colors,
24958         g_type: 'soft',
24959         g_gutter: '20%'
24960
24961     },
24962     title : false,
24963
24964     getAutoCreate : function(){
24965         
24966         var cfg = {
24967             tag: 'div',
24968             html : null
24969         };
24970         
24971         
24972         return  cfg;
24973     },
24974
24975     onRender : function(ct,position){
24976         
24977         
24978         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24979         
24980         if (typeof(Raphael) == 'undefined') {
24981             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24982             return;
24983         }
24984         
24985         this.raphael = Raphael(this.el.dom);
24986         
24987                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24988                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24989                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24990                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24991                 /*
24992                 r.text(160, 10, "Single Series Chart").attr(txtattr);
24993                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
24994                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
24995                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
24996                 
24997                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
24998                 r.barchart(330, 10, 300, 220, data1);
24999                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25000                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25001                 */
25002                 
25003                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25004                 // r.barchart(30, 30, 560, 250,  xdata, {
25005                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25006                 //     axis : "0 0 1 1",
25007                 //     axisxlabels :  xdata
25008                 //     //yvalues : cols,
25009                    
25010                 // });
25011 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25012 //        
25013 //        this.load(null,xdata,{
25014 //                axis : "0 0 1 1",
25015 //                axisxlabels :  xdata
25016 //                });
25017
25018     },
25019
25020     load : function(graphtype,xdata,opts)
25021     {
25022         this.raphael.clear();
25023         if(!graphtype) {
25024             graphtype = this.graphtype;
25025         }
25026         if(!opts){
25027             opts = this.opts;
25028         }
25029         var r = this.raphael,
25030             fin = function () {
25031                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25032             },
25033             fout = function () {
25034                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25035             },
25036             pfin = function() {
25037                 this.sector.stop();
25038                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25039
25040                 if (this.label) {
25041                     this.label[0].stop();
25042                     this.label[0].attr({ r: 7.5 });
25043                     this.label[1].attr({ "font-weight": 800 });
25044                 }
25045             },
25046             pfout = function() {
25047                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25048
25049                 if (this.label) {
25050                     this.label[0].animate({ r: 5 }, 500, "bounce");
25051                     this.label[1].attr({ "font-weight": 400 });
25052                 }
25053             };
25054
25055         switch(graphtype){
25056             case 'bar':
25057                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25058                 break;
25059             case 'hbar':
25060                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25061                 break;
25062             case 'pie':
25063 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
25064 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25065 //            
25066                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25067                 
25068                 break;
25069
25070         }
25071         
25072         if(this.title){
25073             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25074         }
25075         
25076     },
25077     
25078     setTitle: function(o)
25079     {
25080         this.title = o;
25081     },
25082     
25083     initEvents: function() {
25084         
25085         if(!this.href){
25086             this.el.on('click', this.onClick, this);
25087         }
25088     },
25089     
25090     onClick : function(e)
25091     {
25092         Roo.log('img onclick');
25093         this.fireEvent('click', this, e);
25094     }
25095    
25096 });
25097
25098  
25099 /*
25100  * - LGPL
25101  *
25102  * numberBox
25103  * 
25104  */
25105 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25106
25107 /**
25108  * @class Roo.bootstrap.dash.NumberBox
25109  * @extends Roo.bootstrap.Component
25110  * Bootstrap NumberBox class
25111  * @cfg {String} headline Box headline
25112  * @cfg {String} content Box content
25113  * @cfg {String} icon Box icon
25114  * @cfg {String} footer Footer text
25115  * @cfg {String} fhref Footer href
25116  * 
25117  * @constructor
25118  * Create a new NumberBox
25119  * @param {Object} config The config object
25120  */
25121
25122
25123 Roo.bootstrap.dash.NumberBox = function(config){
25124     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25125     
25126 };
25127
25128 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
25129     
25130     headline : '',
25131     content : '',
25132     icon : '',
25133     footer : '',
25134     fhref : '',
25135     ficon : '',
25136     
25137     getAutoCreate : function(){
25138         
25139         var cfg = {
25140             tag : 'div',
25141             cls : 'small-box ',
25142             cn : [
25143                 {
25144                     tag : 'div',
25145                     cls : 'inner',
25146                     cn :[
25147                         {
25148                             tag : 'h3',
25149                             cls : 'roo-headline',
25150                             html : this.headline
25151                         },
25152                         {
25153                             tag : 'p',
25154                             cls : 'roo-content',
25155                             html : this.content
25156                         }
25157                     ]
25158                 }
25159             ]
25160         };
25161         
25162         if(this.icon){
25163             cfg.cn.push({
25164                 tag : 'div',
25165                 cls : 'icon',
25166                 cn :[
25167                     {
25168                         tag : 'i',
25169                         cls : 'ion ' + this.icon
25170                     }
25171                 ]
25172             });
25173         }
25174         
25175         if(this.footer){
25176             var footer = {
25177                 tag : 'a',
25178                 cls : 'small-box-footer',
25179                 href : this.fhref || '#',
25180                 html : this.footer
25181             };
25182             
25183             cfg.cn.push(footer);
25184             
25185         }
25186         
25187         return  cfg;
25188     },
25189
25190     onRender : function(ct,position){
25191         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25192
25193
25194        
25195                 
25196     },
25197
25198     setHeadline: function (value)
25199     {
25200         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25201     },
25202     
25203     setFooter: function (value, href)
25204     {
25205         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25206         
25207         if(href){
25208             this.el.select('a.small-box-footer',true).first().attr('href', href);
25209         }
25210         
25211     },
25212
25213     setContent: function (value)
25214     {
25215         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25216     },
25217
25218     initEvents: function() 
25219     {   
25220         
25221     }
25222     
25223 });
25224
25225  
25226 /*
25227  * - LGPL
25228  *
25229  * TabBox
25230  * 
25231  */
25232 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25233
25234 /**
25235  * @class Roo.bootstrap.dash.TabBox
25236  * @extends Roo.bootstrap.Component
25237  * Bootstrap TabBox class
25238  * @cfg {String} title Title of the TabBox
25239  * @cfg {String} icon Icon of the TabBox
25240  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25241  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25242  * 
25243  * @constructor
25244  * Create a new TabBox
25245  * @param {Object} config The config object
25246  */
25247
25248
25249 Roo.bootstrap.dash.TabBox = function(config){
25250     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25251     this.addEvents({
25252         // raw events
25253         /**
25254          * @event addpane
25255          * When a pane is added
25256          * @param {Roo.bootstrap.dash.TabPane} pane
25257          */
25258         "addpane" : true,
25259         /**
25260          * @event activatepane
25261          * When a pane is activated
25262          * @param {Roo.bootstrap.dash.TabPane} pane
25263          */
25264         "activatepane" : true
25265         
25266          
25267     });
25268     
25269     this.panes = [];
25270 };
25271
25272 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25273
25274     title : '',
25275     icon : false,
25276     showtabs : true,
25277     tabScrollable : false,
25278     
25279     getChildContainer : function()
25280     {
25281         return this.el.select('.tab-content', true).first();
25282     },
25283     
25284     getAutoCreate : function(){
25285         
25286         var header = {
25287             tag: 'li',
25288             cls: 'pull-left header',
25289             html: this.title,
25290             cn : []
25291         };
25292         
25293         if(this.icon){
25294             header.cn.push({
25295                 tag: 'i',
25296                 cls: 'fa ' + this.icon
25297             });
25298         }
25299         
25300         var h = {
25301             tag: 'ul',
25302             cls: 'nav nav-tabs pull-right',
25303             cn: [
25304                 header
25305             ]
25306         };
25307         
25308         if(this.tabScrollable){
25309             h = {
25310                 tag: 'div',
25311                 cls: 'tab-header',
25312                 cn: [
25313                     {
25314                         tag: 'ul',
25315                         cls: 'nav nav-tabs pull-right',
25316                         cn: [
25317                             header
25318                         ]
25319                     }
25320                 ]
25321             };
25322         }
25323         
25324         var cfg = {
25325             tag: 'div',
25326             cls: 'nav-tabs-custom',
25327             cn: [
25328                 h,
25329                 {
25330                     tag: 'div',
25331                     cls: 'tab-content no-padding',
25332                     cn: []
25333                 }
25334             ]
25335         };
25336
25337         return  cfg;
25338     },
25339     initEvents : function()
25340     {
25341         //Roo.log('add add pane handler');
25342         this.on('addpane', this.onAddPane, this);
25343     },
25344      /**
25345      * Updates the box title
25346      * @param {String} html to set the title to.
25347      */
25348     setTitle : function(value)
25349     {
25350         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25351     },
25352     onAddPane : function(pane)
25353     {
25354         this.panes.push(pane);
25355         //Roo.log('addpane');
25356         //Roo.log(pane);
25357         // tabs are rendere left to right..
25358         if(!this.showtabs){
25359             return;
25360         }
25361         
25362         var ctr = this.el.select('.nav-tabs', true).first();
25363          
25364          
25365         var existing = ctr.select('.nav-tab',true);
25366         var qty = existing.getCount();;
25367         
25368         
25369         var tab = ctr.createChild({
25370             tag : 'li',
25371             cls : 'nav-tab' + (qty ? '' : ' active'),
25372             cn : [
25373                 {
25374                     tag : 'a',
25375                     href:'#',
25376                     html : pane.title
25377                 }
25378             ]
25379         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25380         pane.tab = tab;
25381         
25382         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25383         if (!qty) {
25384             pane.el.addClass('active');
25385         }
25386         
25387                 
25388     },
25389     onTabClick : function(ev,un,ob,pane)
25390     {
25391         //Roo.log('tab - prev default');
25392         ev.preventDefault();
25393         
25394         
25395         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25396         pane.tab.addClass('active');
25397         //Roo.log(pane.title);
25398         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25399         // technically we should have a deactivate event.. but maybe add later.
25400         // and it should not de-activate the selected tab...
25401         this.fireEvent('activatepane', pane);
25402         pane.el.addClass('active');
25403         pane.fireEvent('activate');
25404         
25405         
25406     },
25407     
25408     getActivePane : function()
25409     {
25410         var r = false;
25411         Roo.each(this.panes, function(p) {
25412             if(p.el.hasClass('active')){
25413                 r = p;
25414                 return false;
25415             }
25416             
25417             return;
25418         });
25419         
25420         return r;
25421     }
25422     
25423     
25424 });
25425
25426  
25427 /*
25428  * - LGPL
25429  *
25430  * Tab pane
25431  * 
25432  */
25433 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25434 /**
25435  * @class Roo.bootstrap.TabPane
25436  * @extends Roo.bootstrap.Component
25437  * Bootstrap TabPane class
25438  * @cfg {Boolean} active (false | true) Default false
25439  * @cfg {String} title title of panel
25440
25441  * 
25442  * @constructor
25443  * Create a new TabPane
25444  * @param {Object} config The config object
25445  */
25446
25447 Roo.bootstrap.dash.TabPane = function(config){
25448     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25449     
25450     this.addEvents({
25451         // raw events
25452         /**
25453          * @event activate
25454          * When a pane is activated
25455          * @param {Roo.bootstrap.dash.TabPane} pane
25456          */
25457         "activate" : true
25458          
25459     });
25460 };
25461
25462 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25463     
25464     active : false,
25465     title : '',
25466     
25467     // the tabBox that this is attached to.
25468     tab : false,
25469      
25470     getAutoCreate : function() 
25471     {
25472         var cfg = {
25473             tag: 'div',
25474             cls: 'tab-pane'
25475         };
25476         
25477         if(this.active){
25478             cfg.cls += ' active';
25479         }
25480         
25481         return cfg;
25482     },
25483     initEvents  : function()
25484     {
25485         //Roo.log('trigger add pane handler');
25486         this.parent().fireEvent('addpane', this)
25487     },
25488     
25489      /**
25490      * Updates the tab title 
25491      * @param {String} html to set the title to.
25492      */
25493     setTitle: function(str)
25494     {
25495         if (!this.tab) {
25496             return;
25497         }
25498         this.title = str;
25499         this.tab.select('a', true).first().dom.innerHTML = str;
25500         
25501     }
25502     
25503     
25504     
25505 });
25506
25507  
25508
25509
25510  /*
25511  * - LGPL
25512  *
25513  * menu
25514  * 
25515  */
25516 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25517
25518 /**
25519  * @class Roo.bootstrap.menu.Menu
25520  * @extends Roo.bootstrap.Component
25521  * Bootstrap Menu class - container for Menu
25522  * @cfg {String} html Text of the menu
25523  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25524  * @cfg {String} icon Font awesome icon
25525  * @cfg {String} pos Menu align to (top | bottom) default bottom
25526  * 
25527  * 
25528  * @constructor
25529  * Create a new Menu
25530  * @param {Object} config The config object
25531  */
25532
25533
25534 Roo.bootstrap.menu.Menu = function(config){
25535     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25536     
25537     this.addEvents({
25538         /**
25539          * @event beforeshow
25540          * Fires before this menu is displayed
25541          * @param {Roo.bootstrap.menu.Menu} this
25542          */
25543         beforeshow : true,
25544         /**
25545          * @event beforehide
25546          * Fires before this menu is hidden
25547          * @param {Roo.bootstrap.menu.Menu} this
25548          */
25549         beforehide : true,
25550         /**
25551          * @event show
25552          * Fires after this menu is displayed
25553          * @param {Roo.bootstrap.menu.Menu} this
25554          */
25555         show : true,
25556         /**
25557          * @event hide
25558          * Fires after this menu is hidden
25559          * @param {Roo.bootstrap.menu.Menu} this
25560          */
25561         hide : true,
25562         /**
25563          * @event click
25564          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25565          * @param {Roo.bootstrap.menu.Menu} this
25566          * @param {Roo.EventObject} e
25567          */
25568         click : true
25569     });
25570     
25571 };
25572
25573 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25574     
25575     submenu : false,
25576     html : '',
25577     weight : 'default',
25578     icon : false,
25579     pos : 'bottom',
25580     
25581     
25582     getChildContainer : function() {
25583         if(this.isSubMenu){
25584             return this.el;
25585         }
25586         
25587         return this.el.select('ul.dropdown-menu', true).first();  
25588     },
25589     
25590     getAutoCreate : function()
25591     {
25592         var text = [
25593             {
25594                 tag : 'span',
25595                 cls : 'roo-menu-text',
25596                 html : this.html
25597             }
25598         ];
25599         
25600         if(this.icon){
25601             text.unshift({
25602                 tag : 'i',
25603                 cls : 'fa ' + this.icon
25604             })
25605         }
25606         
25607         
25608         var cfg = {
25609             tag : 'div',
25610             cls : 'btn-group',
25611             cn : [
25612                 {
25613                     tag : 'button',
25614                     cls : 'dropdown-button btn btn-' + this.weight,
25615                     cn : text
25616                 },
25617                 {
25618                     tag : 'button',
25619                     cls : 'dropdown-toggle btn btn-' + this.weight,
25620                     cn : [
25621                         {
25622                             tag : 'span',
25623                             cls : 'caret'
25624                         }
25625                     ]
25626                 },
25627                 {
25628                     tag : 'ul',
25629                     cls : 'dropdown-menu'
25630                 }
25631             ]
25632             
25633         };
25634         
25635         if(this.pos == 'top'){
25636             cfg.cls += ' dropup';
25637         }
25638         
25639         if(this.isSubMenu){
25640             cfg = {
25641                 tag : 'ul',
25642                 cls : 'dropdown-menu'
25643             }
25644         }
25645         
25646         return cfg;
25647     },
25648     
25649     onRender : function(ct, position)
25650     {
25651         this.isSubMenu = ct.hasClass('dropdown-submenu');
25652         
25653         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25654     },
25655     
25656     initEvents : function() 
25657     {
25658         if(this.isSubMenu){
25659             return;
25660         }
25661         
25662         this.hidden = true;
25663         
25664         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25665         this.triggerEl.on('click', this.onTriggerPress, this);
25666         
25667         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25668         this.buttonEl.on('click', this.onClick, this);
25669         
25670     },
25671     
25672     list : function()
25673     {
25674         if(this.isSubMenu){
25675             return this.el;
25676         }
25677         
25678         return this.el.select('ul.dropdown-menu', true).first();
25679     },
25680     
25681     onClick : function(e)
25682     {
25683         this.fireEvent("click", this, e);
25684     },
25685     
25686     onTriggerPress  : function(e)
25687     {   
25688         if (this.isVisible()) {
25689             this.hide();
25690         } else {
25691             this.show();
25692         }
25693     },
25694     
25695     isVisible : function(){
25696         return !this.hidden;
25697     },
25698     
25699     show : function()
25700     {
25701         this.fireEvent("beforeshow", this);
25702         
25703         this.hidden = false;
25704         this.el.addClass('open');
25705         
25706         Roo.get(document).on("mouseup", this.onMouseUp, this);
25707         
25708         this.fireEvent("show", this);
25709         
25710         
25711     },
25712     
25713     hide : function()
25714     {
25715         this.fireEvent("beforehide", this);
25716         
25717         this.hidden = true;
25718         this.el.removeClass('open');
25719         
25720         Roo.get(document).un("mouseup", this.onMouseUp);
25721         
25722         this.fireEvent("hide", this);
25723     },
25724     
25725     onMouseUp : function()
25726     {
25727         this.hide();
25728     }
25729     
25730 });
25731
25732  
25733  /*
25734  * - LGPL
25735  *
25736  * menu item
25737  * 
25738  */
25739 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25740
25741 /**
25742  * @class Roo.bootstrap.menu.Item
25743  * @extends Roo.bootstrap.Component
25744  * Bootstrap MenuItem class
25745  * @cfg {Boolean} submenu (true | false) default false
25746  * @cfg {String} html text of the item
25747  * @cfg {String} href the link
25748  * @cfg {Boolean} disable (true | false) default false
25749  * @cfg {Boolean} preventDefault (true | false) default true
25750  * @cfg {String} icon Font awesome icon
25751  * @cfg {String} pos Submenu align to (left | right) default right 
25752  * 
25753  * 
25754  * @constructor
25755  * Create a new Item
25756  * @param {Object} config The config object
25757  */
25758
25759
25760 Roo.bootstrap.menu.Item = function(config){
25761     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25762     this.addEvents({
25763         /**
25764          * @event mouseover
25765          * Fires when the mouse is hovering over this menu
25766          * @param {Roo.bootstrap.menu.Item} this
25767          * @param {Roo.EventObject} e
25768          */
25769         mouseover : true,
25770         /**
25771          * @event mouseout
25772          * Fires when the mouse exits this menu
25773          * @param {Roo.bootstrap.menu.Item} this
25774          * @param {Roo.EventObject} e
25775          */
25776         mouseout : true,
25777         // raw events
25778         /**
25779          * @event click
25780          * The raw click event for the entire grid.
25781          * @param {Roo.EventObject} e
25782          */
25783         click : true
25784     });
25785 };
25786
25787 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25788     
25789     submenu : false,
25790     href : '',
25791     html : '',
25792     preventDefault: true,
25793     disable : false,
25794     icon : false,
25795     pos : 'right',
25796     
25797     getAutoCreate : function()
25798     {
25799         var text = [
25800             {
25801                 tag : 'span',
25802                 cls : 'roo-menu-item-text',
25803                 html : this.html
25804             }
25805         ];
25806         
25807         if(this.icon){
25808             text.unshift({
25809                 tag : 'i',
25810                 cls : 'fa ' + this.icon
25811             })
25812         }
25813         
25814         var cfg = {
25815             tag : 'li',
25816             cn : [
25817                 {
25818                     tag : 'a',
25819                     href : this.href || '#',
25820                     cn : text
25821                 }
25822             ]
25823         };
25824         
25825         if(this.disable){
25826             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25827         }
25828         
25829         if(this.submenu){
25830             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25831             
25832             if(this.pos == 'left'){
25833                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25834             }
25835         }
25836         
25837         return cfg;
25838     },
25839     
25840     initEvents : function() 
25841     {
25842         this.el.on('mouseover', this.onMouseOver, this);
25843         this.el.on('mouseout', this.onMouseOut, this);
25844         
25845         this.el.select('a', true).first().on('click', this.onClick, this);
25846         
25847     },
25848     
25849     onClick : function(e)
25850     {
25851         if(this.preventDefault){
25852             e.preventDefault();
25853         }
25854         
25855         this.fireEvent("click", this, e);
25856     },
25857     
25858     onMouseOver : function(e)
25859     {
25860         if(this.submenu && this.pos == 'left'){
25861             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25862         }
25863         
25864         this.fireEvent("mouseover", this, e);
25865     },
25866     
25867     onMouseOut : function(e)
25868     {
25869         this.fireEvent("mouseout", this, e);
25870     }
25871 });
25872
25873  
25874
25875  /*
25876  * - LGPL
25877  *
25878  * menu separator
25879  * 
25880  */
25881 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25882
25883 /**
25884  * @class Roo.bootstrap.menu.Separator
25885  * @extends Roo.bootstrap.Component
25886  * Bootstrap Separator class
25887  * 
25888  * @constructor
25889  * Create a new Separator
25890  * @param {Object} config The config object
25891  */
25892
25893
25894 Roo.bootstrap.menu.Separator = function(config){
25895     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25896 };
25897
25898 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25899     
25900     getAutoCreate : function(){
25901         var cfg = {
25902             tag : 'li',
25903             cls: 'divider'
25904         };
25905         
25906         return cfg;
25907     }
25908    
25909 });
25910
25911  
25912
25913  /*
25914  * - LGPL
25915  *
25916  * Tooltip
25917  * 
25918  */
25919
25920 /**
25921  * @class Roo.bootstrap.Tooltip
25922  * Bootstrap Tooltip class
25923  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25924  * to determine which dom element triggers the tooltip.
25925  * 
25926  * It needs to add support for additional attributes like tooltip-position
25927  * 
25928  * @constructor
25929  * Create a new Toolti
25930  * @param {Object} config The config object
25931  */
25932
25933 Roo.bootstrap.Tooltip = function(config){
25934     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25935     
25936     this.alignment = Roo.bootstrap.Tooltip.alignment;
25937     
25938     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25939         this.alignment = config.alignment;
25940     }
25941     
25942 };
25943
25944 Roo.apply(Roo.bootstrap.Tooltip, {
25945     /**
25946      * @function init initialize tooltip monitoring.
25947      * @static
25948      */
25949     currentEl : false,
25950     currentTip : false,
25951     currentRegion : false,
25952     
25953     //  init : delay?
25954     
25955     init : function()
25956     {
25957         Roo.get(document).on('mouseover', this.enter ,this);
25958         Roo.get(document).on('mouseout', this.leave, this);
25959          
25960         
25961         this.currentTip = new Roo.bootstrap.Tooltip();
25962     },
25963     
25964     enter : function(ev)
25965     {
25966         var dom = ev.getTarget();
25967         
25968         //Roo.log(['enter',dom]);
25969         var el = Roo.fly(dom);
25970         if (this.currentEl) {
25971             //Roo.log(dom);
25972             //Roo.log(this.currentEl);
25973             //Roo.log(this.currentEl.contains(dom));
25974             if (this.currentEl == el) {
25975                 return;
25976             }
25977             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25978                 return;
25979             }
25980
25981         }
25982         
25983         if (this.currentTip.el) {
25984             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25985         }    
25986         //Roo.log(ev);
25987         
25988         if(!el || el.dom == document){
25989             return;
25990         }
25991         
25992         var bindEl = el;
25993         
25994         // you can not look for children, as if el is the body.. then everythign is the child..
25995         if (!el.attr('tooltip')) { //
25996             if (!el.select("[tooltip]").elements.length) {
25997                 return;
25998             }
25999             // is the mouse over this child...?
26000             bindEl = el.select("[tooltip]").first();
26001             var xy = ev.getXY();
26002             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26003                 //Roo.log("not in region.");
26004                 return;
26005             }
26006             //Roo.log("child element over..");
26007             
26008         }
26009         this.currentEl = bindEl;
26010         this.currentTip.bind(bindEl);
26011         this.currentRegion = Roo.lib.Region.getRegion(dom);
26012         this.currentTip.enter();
26013         
26014     },
26015     leave : function(ev)
26016     {
26017         var dom = ev.getTarget();
26018         //Roo.log(['leave',dom]);
26019         if (!this.currentEl) {
26020             return;
26021         }
26022         
26023         
26024         if (dom != this.currentEl.dom) {
26025             return;
26026         }
26027         var xy = ev.getXY();
26028         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
26029             return;
26030         }
26031         // only activate leave if mouse cursor is outside... bounding box..
26032         
26033         
26034         
26035         
26036         if (this.currentTip) {
26037             this.currentTip.leave();
26038         }
26039         //Roo.log('clear currentEl');
26040         this.currentEl = false;
26041         
26042         
26043     },
26044     alignment : {
26045         'left' : ['r-l', [-2,0], 'right'],
26046         'right' : ['l-r', [2,0], 'left'],
26047         'bottom' : ['t-b', [0,2], 'top'],
26048         'top' : [ 'b-t', [0,-2], 'bottom']
26049     }
26050     
26051 });
26052
26053
26054 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
26055     
26056     
26057     bindEl : false,
26058     
26059     delay : null, // can be { show : 300 , hide: 500}
26060     
26061     timeout : null,
26062     
26063     hoverState : null, //???
26064     
26065     placement : 'bottom', 
26066     
26067     alignment : false,
26068     
26069     getAutoCreate : function(){
26070     
26071         var cfg = {
26072            cls : 'tooltip',
26073            role : 'tooltip',
26074            cn : [
26075                 {
26076                     cls : 'tooltip-arrow'
26077                 },
26078                 {
26079                     cls : 'tooltip-inner'
26080                 }
26081            ]
26082         };
26083         
26084         return cfg;
26085     },
26086     bind : function(el)
26087     {
26088         this.bindEl = el;
26089     },
26090       
26091     
26092     enter : function () {
26093        
26094         if (this.timeout != null) {
26095             clearTimeout(this.timeout);
26096         }
26097         
26098         this.hoverState = 'in';
26099          //Roo.log("enter - show");
26100         if (!this.delay || !this.delay.show) {
26101             this.show();
26102             return;
26103         }
26104         var _t = this;
26105         this.timeout = setTimeout(function () {
26106             if (_t.hoverState == 'in') {
26107                 _t.show();
26108             }
26109         }, this.delay.show);
26110     },
26111     leave : function()
26112     {
26113         clearTimeout(this.timeout);
26114     
26115         this.hoverState = 'out';
26116          if (!this.delay || !this.delay.hide) {
26117             this.hide();
26118             return;
26119         }
26120        
26121         var _t = this;
26122         this.timeout = setTimeout(function () {
26123             //Roo.log("leave - timeout");
26124             
26125             if (_t.hoverState == 'out') {
26126                 _t.hide();
26127                 Roo.bootstrap.Tooltip.currentEl = false;
26128             }
26129         }, delay);
26130     },
26131     
26132     show : function (msg)
26133     {
26134         if (!this.el) {
26135             this.render(document.body);
26136         }
26137         // set content.
26138         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26139         
26140         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26141         
26142         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26143         
26144         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26145         
26146         var placement = typeof this.placement == 'function' ?
26147             this.placement.call(this, this.el, on_el) :
26148             this.placement;
26149             
26150         var autoToken = /\s?auto?\s?/i;
26151         var autoPlace = autoToken.test(placement);
26152         if (autoPlace) {
26153             placement = placement.replace(autoToken, '') || 'top';
26154         }
26155         
26156         //this.el.detach()
26157         //this.el.setXY([0,0]);
26158         this.el.show();
26159         //this.el.dom.style.display='block';
26160         
26161         //this.el.appendTo(on_el);
26162         
26163         var p = this.getPosition();
26164         var box = this.el.getBox();
26165         
26166         if (autoPlace) {
26167             // fixme..
26168         }
26169         
26170         var align = this.alignment[placement];
26171         
26172         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26173         
26174         if(placement == 'top' || placement == 'bottom'){
26175             if(xy[0] < 0){
26176                 placement = 'right';
26177             }
26178             
26179             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26180                 placement = 'left';
26181             }
26182             
26183             var scroll = Roo.select('body', true).first().getScroll();
26184             
26185             if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26186                 placement = 'top';
26187             }
26188             
26189         }
26190         
26191         this.el.alignTo(this.bindEl, align[0],align[1]);
26192         //var arrow = this.el.select('.arrow',true).first();
26193         //arrow.set(align[2], 
26194         
26195         this.el.addClass(placement);
26196         
26197         this.el.addClass('in fade');
26198         
26199         this.hoverState = null;
26200         
26201         if (this.el.hasClass('fade')) {
26202             // fade it?
26203         }
26204         
26205     },
26206     hide : function()
26207     {
26208          
26209         if (!this.el) {
26210             return;
26211         }
26212         //this.el.setXY([0,0]);
26213         this.el.removeClass('in');
26214         //this.el.hide();
26215         
26216     }
26217     
26218 });
26219  
26220
26221  /*
26222  * - LGPL
26223  *
26224  * Location Picker
26225  * 
26226  */
26227
26228 /**
26229  * @class Roo.bootstrap.LocationPicker
26230  * @extends Roo.bootstrap.Component
26231  * Bootstrap LocationPicker class
26232  * @cfg {Number} latitude Position when init default 0
26233  * @cfg {Number} longitude Position when init default 0
26234  * @cfg {Number} zoom default 15
26235  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26236  * @cfg {Boolean} mapTypeControl default false
26237  * @cfg {Boolean} disableDoubleClickZoom default false
26238  * @cfg {Boolean} scrollwheel default true
26239  * @cfg {Boolean} streetViewControl default false
26240  * @cfg {Number} radius default 0
26241  * @cfg {String} locationName
26242  * @cfg {Boolean} draggable default true
26243  * @cfg {Boolean} enableAutocomplete default false
26244  * @cfg {Boolean} enableReverseGeocode default true
26245  * @cfg {String} markerTitle
26246  * 
26247  * @constructor
26248  * Create a new LocationPicker
26249  * @param {Object} config The config object
26250  */
26251
26252
26253 Roo.bootstrap.LocationPicker = function(config){
26254     
26255     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26256     
26257     this.addEvents({
26258         /**
26259          * @event initial
26260          * Fires when the picker initialized.
26261          * @param {Roo.bootstrap.LocationPicker} this
26262          * @param {Google Location} location
26263          */
26264         initial : true,
26265         /**
26266          * @event positionchanged
26267          * Fires when the picker position changed.
26268          * @param {Roo.bootstrap.LocationPicker} this
26269          * @param {Google Location} location
26270          */
26271         positionchanged : true,
26272         /**
26273          * @event resize
26274          * Fires when the map resize.
26275          * @param {Roo.bootstrap.LocationPicker} this
26276          */
26277         resize : true,
26278         /**
26279          * @event show
26280          * Fires when the map show.
26281          * @param {Roo.bootstrap.LocationPicker} this
26282          */
26283         show : true,
26284         /**
26285          * @event hide
26286          * Fires when the map hide.
26287          * @param {Roo.bootstrap.LocationPicker} this
26288          */
26289         hide : true,
26290         /**
26291          * @event mapClick
26292          * Fires when click the map.
26293          * @param {Roo.bootstrap.LocationPicker} this
26294          * @param {Map event} e
26295          */
26296         mapClick : true,
26297         /**
26298          * @event mapRightClick
26299          * Fires when right click the map.
26300          * @param {Roo.bootstrap.LocationPicker} this
26301          * @param {Map event} e
26302          */
26303         mapRightClick : true,
26304         /**
26305          * @event markerClick
26306          * Fires when click the marker.
26307          * @param {Roo.bootstrap.LocationPicker} this
26308          * @param {Map event} e
26309          */
26310         markerClick : true,
26311         /**
26312          * @event markerRightClick
26313          * Fires when right click the marker.
26314          * @param {Roo.bootstrap.LocationPicker} this
26315          * @param {Map event} e
26316          */
26317         markerRightClick : true,
26318         /**
26319          * @event OverlayViewDraw
26320          * Fires when OverlayView Draw
26321          * @param {Roo.bootstrap.LocationPicker} this
26322          */
26323         OverlayViewDraw : true,
26324         /**
26325          * @event OverlayViewOnAdd
26326          * Fires when OverlayView Draw
26327          * @param {Roo.bootstrap.LocationPicker} this
26328          */
26329         OverlayViewOnAdd : true,
26330         /**
26331          * @event OverlayViewOnRemove
26332          * Fires when OverlayView Draw
26333          * @param {Roo.bootstrap.LocationPicker} this
26334          */
26335         OverlayViewOnRemove : true,
26336         /**
26337          * @event OverlayViewShow
26338          * Fires when OverlayView Draw
26339          * @param {Roo.bootstrap.LocationPicker} this
26340          * @param {Pixel} cpx
26341          */
26342         OverlayViewShow : true,
26343         /**
26344          * @event OverlayViewHide
26345          * Fires when OverlayView Draw
26346          * @param {Roo.bootstrap.LocationPicker} this
26347          */
26348         OverlayViewHide : true,
26349         /**
26350          * @event loadexception
26351          * Fires when load google lib failed.
26352          * @param {Roo.bootstrap.LocationPicker} this
26353          */
26354         loadexception : true
26355     });
26356         
26357 };
26358
26359 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26360     
26361     gMapContext: false,
26362     
26363     latitude: 0,
26364     longitude: 0,
26365     zoom: 15,
26366     mapTypeId: false,
26367     mapTypeControl: false,
26368     disableDoubleClickZoom: false,
26369     scrollwheel: true,
26370     streetViewControl: false,
26371     radius: 0,
26372     locationName: '',
26373     draggable: true,
26374     enableAutocomplete: false,
26375     enableReverseGeocode: true,
26376     markerTitle: '',
26377     
26378     getAutoCreate: function()
26379     {
26380
26381         var cfg = {
26382             tag: 'div',
26383             cls: 'roo-location-picker'
26384         };
26385         
26386         return cfg
26387     },
26388     
26389     initEvents: function(ct, position)
26390     {       
26391         if(!this.el.getWidth() || this.isApplied()){
26392             return;
26393         }
26394         
26395         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26396         
26397         this.initial();
26398     },
26399     
26400     initial: function()
26401     {
26402         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26403             this.fireEvent('loadexception', this);
26404             return;
26405         }
26406         
26407         if(!this.mapTypeId){
26408             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26409         }
26410         
26411         this.gMapContext = this.GMapContext();
26412         
26413         this.initOverlayView();
26414         
26415         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26416         
26417         var _this = this;
26418                 
26419         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26420             _this.setPosition(_this.gMapContext.marker.position);
26421         });
26422         
26423         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26424             _this.fireEvent('mapClick', this, event);
26425             
26426         });
26427
26428         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26429             _this.fireEvent('mapRightClick', this, event);
26430             
26431         });
26432         
26433         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26434             _this.fireEvent('markerClick', this, event);
26435             
26436         });
26437
26438         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26439             _this.fireEvent('markerRightClick', this, event);
26440             
26441         });
26442         
26443         this.setPosition(this.gMapContext.location);
26444         
26445         this.fireEvent('initial', this, this.gMapContext.location);
26446     },
26447     
26448     initOverlayView: function()
26449     {
26450         var _this = this;
26451         
26452         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26453             
26454             draw: function()
26455             {
26456                 _this.fireEvent('OverlayViewDraw', _this);
26457             },
26458             
26459             onAdd: function()
26460             {
26461                 _this.fireEvent('OverlayViewOnAdd', _this);
26462             },
26463             
26464             onRemove: function()
26465             {
26466                 _this.fireEvent('OverlayViewOnRemove', _this);
26467             },
26468             
26469             show: function(cpx)
26470             {
26471                 _this.fireEvent('OverlayViewShow', _this, cpx);
26472             },
26473             
26474             hide: function()
26475             {
26476                 _this.fireEvent('OverlayViewHide', _this);
26477             }
26478             
26479         });
26480     },
26481     
26482     fromLatLngToContainerPixel: function(event)
26483     {
26484         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26485     },
26486     
26487     isApplied: function() 
26488     {
26489         return this.getGmapContext() == false ? false : true;
26490     },
26491     
26492     getGmapContext: function() 
26493     {
26494         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26495     },
26496     
26497     GMapContext: function() 
26498     {
26499         var position = new google.maps.LatLng(this.latitude, this.longitude);
26500         
26501         var _map = new google.maps.Map(this.el.dom, {
26502             center: position,
26503             zoom: this.zoom,
26504             mapTypeId: this.mapTypeId,
26505             mapTypeControl: this.mapTypeControl,
26506             disableDoubleClickZoom: this.disableDoubleClickZoom,
26507             scrollwheel: this.scrollwheel,
26508             streetViewControl: this.streetViewControl,
26509             locationName: this.locationName,
26510             draggable: this.draggable,
26511             enableAutocomplete: this.enableAutocomplete,
26512             enableReverseGeocode: this.enableReverseGeocode
26513         });
26514         
26515         var _marker = new google.maps.Marker({
26516             position: position,
26517             map: _map,
26518             title: this.markerTitle,
26519             draggable: this.draggable
26520         });
26521         
26522         return {
26523             map: _map,
26524             marker: _marker,
26525             circle: null,
26526             location: position,
26527             radius: this.radius,
26528             locationName: this.locationName,
26529             addressComponents: {
26530                 formatted_address: null,
26531                 addressLine1: null,
26532                 addressLine2: null,
26533                 streetName: null,
26534                 streetNumber: null,
26535                 city: null,
26536                 district: null,
26537                 state: null,
26538                 stateOrProvince: null
26539             },
26540             settings: this,
26541             domContainer: this.el.dom,
26542             geodecoder: new google.maps.Geocoder()
26543         };
26544     },
26545     
26546     drawCircle: function(center, radius, options) 
26547     {
26548         if (this.gMapContext.circle != null) {
26549             this.gMapContext.circle.setMap(null);
26550         }
26551         if (radius > 0) {
26552             radius *= 1;
26553             options = Roo.apply({}, options, {
26554                 strokeColor: "#0000FF",
26555                 strokeOpacity: .35,
26556                 strokeWeight: 2,
26557                 fillColor: "#0000FF",
26558                 fillOpacity: .2
26559             });
26560             
26561             options.map = this.gMapContext.map;
26562             options.radius = radius;
26563             options.center = center;
26564             this.gMapContext.circle = new google.maps.Circle(options);
26565             return this.gMapContext.circle;
26566         }
26567         
26568         return null;
26569     },
26570     
26571     setPosition: function(location) 
26572     {
26573         this.gMapContext.location = location;
26574         this.gMapContext.marker.setPosition(location);
26575         this.gMapContext.map.panTo(location);
26576         this.drawCircle(location, this.gMapContext.radius, {});
26577         
26578         var _this = this;
26579         
26580         if (this.gMapContext.settings.enableReverseGeocode) {
26581             this.gMapContext.geodecoder.geocode({
26582                 latLng: this.gMapContext.location
26583             }, function(results, status) {
26584                 
26585                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26586                     _this.gMapContext.locationName = results[0].formatted_address;
26587                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26588                     
26589                     _this.fireEvent('positionchanged', this, location);
26590                 }
26591             });
26592             
26593             return;
26594         }
26595         
26596         this.fireEvent('positionchanged', this, location);
26597     },
26598     
26599     resize: function()
26600     {
26601         google.maps.event.trigger(this.gMapContext.map, "resize");
26602         
26603         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26604         
26605         this.fireEvent('resize', this);
26606     },
26607     
26608     setPositionByLatLng: function(latitude, longitude)
26609     {
26610         this.setPosition(new google.maps.LatLng(latitude, longitude));
26611     },
26612     
26613     getCurrentPosition: function() 
26614     {
26615         return {
26616             latitude: this.gMapContext.location.lat(),
26617             longitude: this.gMapContext.location.lng()
26618         };
26619     },
26620     
26621     getAddressName: function() 
26622     {
26623         return this.gMapContext.locationName;
26624     },
26625     
26626     getAddressComponents: function() 
26627     {
26628         return this.gMapContext.addressComponents;
26629     },
26630     
26631     address_component_from_google_geocode: function(address_components) 
26632     {
26633         var result = {};
26634         
26635         for (var i = 0; i < address_components.length; i++) {
26636             var component = address_components[i];
26637             if (component.types.indexOf("postal_code") >= 0) {
26638                 result.postalCode = component.short_name;
26639             } else if (component.types.indexOf("street_number") >= 0) {
26640                 result.streetNumber = component.short_name;
26641             } else if (component.types.indexOf("route") >= 0) {
26642                 result.streetName = component.short_name;
26643             } else if (component.types.indexOf("neighborhood") >= 0) {
26644                 result.city = component.short_name;
26645             } else if (component.types.indexOf("locality") >= 0) {
26646                 result.city = component.short_name;
26647             } else if (component.types.indexOf("sublocality") >= 0) {
26648                 result.district = component.short_name;
26649             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26650                 result.stateOrProvince = component.short_name;
26651             } else if (component.types.indexOf("country") >= 0) {
26652                 result.country = component.short_name;
26653             }
26654         }
26655         
26656         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26657         result.addressLine2 = "";
26658         return result;
26659     },
26660     
26661     setZoomLevel: function(zoom)
26662     {
26663         this.gMapContext.map.setZoom(zoom);
26664     },
26665     
26666     show: function()
26667     {
26668         if(!this.el){
26669             return;
26670         }
26671         
26672         this.el.show();
26673         
26674         this.resize();
26675         
26676         this.fireEvent('show', this);
26677     },
26678     
26679     hide: function()
26680     {
26681         if(!this.el){
26682             return;
26683         }
26684         
26685         this.el.hide();
26686         
26687         this.fireEvent('hide', this);
26688     }
26689     
26690 });
26691
26692 Roo.apply(Roo.bootstrap.LocationPicker, {
26693     
26694     OverlayView : function(map, options)
26695     {
26696         options = options || {};
26697         
26698         this.setMap(map);
26699     }
26700     
26701     
26702 });/*
26703  * - LGPL
26704  *
26705  * Alert
26706  * 
26707  */
26708
26709 /**
26710  * @class Roo.bootstrap.Alert
26711  * @extends Roo.bootstrap.Component
26712  * Bootstrap Alert class
26713  * @cfg {String} title The title of alert
26714  * @cfg {String} html The content of alert
26715  * @cfg {String} weight (  success | info | warning | danger )
26716  * @cfg {String} faicon font-awesomeicon
26717  * 
26718  * @constructor
26719  * Create a new alert
26720  * @param {Object} config The config object
26721  */
26722
26723
26724 Roo.bootstrap.Alert = function(config){
26725     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26726     
26727 };
26728
26729 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26730     
26731     title: '',
26732     html: '',
26733     weight: false,
26734     faicon: false,
26735     
26736     getAutoCreate : function()
26737     {
26738         
26739         var cfg = {
26740             tag : 'div',
26741             cls : 'alert',
26742             cn : [
26743                 {
26744                     tag : 'i',
26745                     cls : 'roo-alert-icon'
26746                     
26747                 },
26748                 {
26749                     tag : 'b',
26750                     cls : 'roo-alert-title',
26751                     html : this.title
26752                 },
26753                 {
26754                     tag : 'span',
26755                     cls : 'roo-alert-text',
26756                     html : this.html
26757                 }
26758             ]
26759         };
26760         
26761         if(this.faicon){
26762             cfg.cn[0].cls += ' fa ' + this.faicon;
26763         }
26764         
26765         if(this.weight){
26766             cfg.cls += ' alert-' + this.weight;
26767         }
26768         
26769         return cfg;
26770     },
26771     
26772     initEvents: function() 
26773     {
26774         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26775     },
26776     
26777     setTitle : function(str)
26778     {
26779         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26780     },
26781     
26782     setText : function(str)
26783     {
26784         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26785     },
26786     
26787     setWeight : function(weight)
26788     {
26789         if(this.weight){
26790             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26791         }
26792         
26793         this.weight = weight;
26794         
26795         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26796     },
26797     
26798     setIcon : function(icon)
26799     {
26800         if(this.faicon){
26801             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26802         }
26803         
26804         this.faicon = icon;
26805         
26806         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26807     },
26808     
26809     hide: function() 
26810     {
26811         this.el.hide();   
26812     },
26813     
26814     show: function() 
26815     {  
26816         this.el.show();   
26817     }
26818     
26819 });
26820
26821  
26822 /*
26823 * Licence: LGPL
26824 */
26825
26826 /**
26827  * @class Roo.bootstrap.UploadCropbox
26828  * @extends Roo.bootstrap.Component
26829  * Bootstrap UploadCropbox class
26830  * @cfg {String} emptyText show when image has been loaded
26831  * @cfg {String} rotateNotify show when image too small to rotate
26832  * @cfg {Number} errorTimeout default 3000
26833  * @cfg {Number} minWidth default 300
26834  * @cfg {Number} minHeight default 300
26835  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26836  * @cfg {Boolean} isDocument (true|false) default false
26837  * @cfg {String} url action url
26838  * @cfg {String} paramName default 'imageUpload'
26839  * @cfg {String} method default POST
26840  * @cfg {Boolean} loadMask (true|false) default true
26841  * @cfg {Boolean} loadingText default 'Loading...'
26842  * 
26843  * @constructor
26844  * Create a new UploadCropbox
26845  * @param {Object} config The config object
26846  */
26847
26848 Roo.bootstrap.UploadCropbox = function(config){
26849     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26850     
26851     this.addEvents({
26852         /**
26853          * @event beforeselectfile
26854          * Fire before select file
26855          * @param {Roo.bootstrap.UploadCropbox} this
26856          */
26857         "beforeselectfile" : true,
26858         /**
26859          * @event initial
26860          * Fire after initEvent
26861          * @param {Roo.bootstrap.UploadCropbox} this
26862          */
26863         "initial" : true,
26864         /**
26865          * @event crop
26866          * Fire after initEvent
26867          * @param {Roo.bootstrap.UploadCropbox} this
26868          * @param {String} data
26869          */
26870         "crop" : true,
26871         /**
26872          * @event prepare
26873          * Fire when preparing the file data
26874          * @param {Roo.bootstrap.UploadCropbox} this
26875          * @param {Object} file
26876          */
26877         "prepare" : true,
26878         /**
26879          * @event exception
26880          * Fire when get exception
26881          * @param {Roo.bootstrap.UploadCropbox} this
26882          * @param {XMLHttpRequest} xhr
26883          */
26884         "exception" : true,
26885         /**
26886          * @event beforeloadcanvas
26887          * Fire before load the canvas
26888          * @param {Roo.bootstrap.UploadCropbox} this
26889          * @param {String} src
26890          */
26891         "beforeloadcanvas" : true,
26892         /**
26893          * @event trash
26894          * Fire when trash image
26895          * @param {Roo.bootstrap.UploadCropbox} this
26896          */
26897         "trash" : true,
26898         /**
26899          * @event download
26900          * Fire when download the image
26901          * @param {Roo.bootstrap.UploadCropbox} this
26902          */
26903         "download" : true,
26904         /**
26905          * @event footerbuttonclick
26906          * Fire when footerbuttonclick
26907          * @param {Roo.bootstrap.UploadCropbox} this
26908          * @param {String} type
26909          */
26910         "footerbuttonclick" : true,
26911         /**
26912          * @event resize
26913          * Fire when resize
26914          * @param {Roo.bootstrap.UploadCropbox} this
26915          */
26916         "resize" : true,
26917         /**
26918          * @event rotate
26919          * Fire when rotate the image
26920          * @param {Roo.bootstrap.UploadCropbox} this
26921          * @param {String} pos
26922          */
26923         "rotate" : true,
26924         /**
26925          * @event inspect
26926          * Fire when inspect the file
26927          * @param {Roo.bootstrap.UploadCropbox} this
26928          * @param {Object} file
26929          */
26930         "inspect" : true,
26931         /**
26932          * @event upload
26933          * Fire when xhr upload the file
26934          * @param {Roo.bootstrap.UploadCropbox} this
26935          * @param {Object} data
26936          */
26937         "upload" : true,
26938         /**
26939          * @event arrange
26940          * Fire when arrange the file data
26941          * @param {Roo.bootstrap.UploadCropbox} this
26942          * @param {Object} formData
26943          */
26944         "arrange" : true
26945     });
26946     
26947     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26948 };
26949
26950 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26951     
26952     emptyText : 'Click to upload image',
26953     rotateNotify : 'Image is too small to rotate',
26954     errorTimeout : 3000,
26955     scale : 0,
26956     baseScale : 1,
26957     rotate : 0,
26958     dragable : false,
26959     pinching : false,
26960     mouseX : 0,
26961     mouseY : 0,
26962     cropData : false,
26963     minWidth : 300,
26964     minHeight : 300,
26965     file : false,
26966     exif : {},
26967     baseRotate : 1,
26968     cropType : 'image/jpeg',
26969     buttons : false,
26970     canvasLoaded : false,
26971     isDocument : false,
26972     method : 'POST',
26973     paramName : 'imageUpload',
26974     loadMask : true,
26975     loadingText : 'Loading...',
26976     maskEl : false,
26977     
26978     getAutoCreate : function()
26979     {
26980         var cfg = {
26981             tag : 'div',
26982             cls : 'roo-upload-cropbox',
26983             cn : [
26984                 {
26985                     tag : 'input',
26986                     cls : 'roo-upload-cropbox-selector',
26987                     type : 'file'
26988                 },
26989                 {
26990                     tag : 'div',
26991                     cls : 'roo-upload-cropbox-body',
26992                     style : 'cursor:pointer',
26993                     cn : [
26994                         {
26995                             tag : 'div',
26996                             cls : 'roo-upload-cropbox-preview'
26997                         },
26998                         {
26999                             tag : 'div',
27000                             cls : 'roo-upload-cropbox-thumb'
27001                         },
27002                         {
27003                             tag : 'div',
27004                             cls : 'roo-upload-cropbox-empty-notify',
27005                             html : this.emptyText
27006                         },
27007                         {
27008                             tag : 'div',
27009                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27010                             html : this.rotateNotify
27011                         }
27012                     ]
27013                 },
27014                 {
27015                     tag : 'div',
27016                     cls : 'roo-upload-cropbox-footer',
27017                     cn : {
27018                         tag : 'div',
27019                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27020                         cn : []
27021                     }
27022                 }
27023             ]
27024         };
27025         
27026         return cfg;
27027     },
27028     
27029     onRender : function(ct, position)
27030     {
27031         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27032         
27033         if (this.buttons.length) {
27034             
27035             Roo.each(this.buttons, function(bb) {
27036                 
27037                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27038                 
27039                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27040                 
27041             }, this);
27042         }
27043         
27044         if(this.loadMask){
27045             this.maskEl = this.el;
27046         }
27047     },
27048     
27049     initEvents : function()
27050     {
27051         this.urlAPI = (window.createObjectURL && window) || 
27052                                 (window.URL && URL.revokeObjectURL && URL) || 
27053                                 (window.webkitURL && webkitURL);
27054                         
27055         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27056         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27057         
27058         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27059         this.selectorEl.hide();
27060         
27061         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27062         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27063         
27064         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27065         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27066         this.thumbEl.hide();
27067         
27068         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27069         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27070         
27071         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27072         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27073         this.errorEl.hide();
27074         
27075         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27076         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27077         this.footerEl.hide();
27078         
27079         this.setThumbBoxSize();
27080         
27081         this.bind();
27082         
27083         this.resize();
27084         
27085         this.fireEvent('initial', this);
27086     },
27087
27088     bind : function()
27089     {
27090         var _this = this;
27091         
27092         window.addEventListener("resize", function() { _this.resize(); } );
27093         
27094         this.bodyEl.on('click', this.beforeSelectFile, this);
27095         
27096         if(Roo.isTouch){
27097             this.bodyEl.on('touchstart', this.onTouchStart, this);
27098             this.bodyEl.on('touchmove', this.onTouchMove, this);
27099             this.bodyEl.on('touchend', this.onTouchEnd, this);
27100         }
27101         
27102         if(!Roo.isTouch){
27103             this.bodyEl.on('mousedown', this.onMouseDown, this);
27104             this.bodyEl.on('mousemove', this.onMouseMove, this);
27105             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27106             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27107             Roo.get(document).on('mouseup', this.onMouseUp, this);
27108         }
27109         
27110         this.selectorEl.on('change', this.onFileSelected, this);
27111     },
27112     
27113     reset : function()
27114     {    
27115         this.scale = 0;
27116         this.baseScale = 1;
27117         this.rotate = 0;
27118         this.baseRotate = 1;
27119         this.dragable = false;
27120         this.pinching = false;
27121         this.mouseX = 0;
27122         this.mouseY = 0;
27123         this.cropData = false;
27124         this.notifyEl.dom.innerHTML = this.emptyText;
27125         
27126         this.selectorEl.dom.value = '';
27127         
27128     },
27129     
27130     resize : function()
27131     {
27132         if(this.fireEvent('resize', this) != false){
27133             this.setThumbBoxPosition();
27134             this.setCanvasPosition();
27135         }
27136     },
27137     
27138     onFooterButtonClick : function(e, el, o, type)
27139     {
27140         switch (type) {
27141             case 'rotate-left' :
27142                 this.onRotateLeft(e);
27143                 break;
27144             case 'rotate-right' :
27145                 this.onRotateRight(e);
27146                 break;
27147             case 'picture' :
27148                 this.beforeSelectFile(e);
27149                 break;
27150             case 'trash' :
27151                 this.trash(e);
27152                 break;
27153             case 'crop' :
27154                 this.crop(e);
27155                 break;
27156             case 'download' :
27157                 this.download(e);
27158                 break;
27159             default :
27160                 break;
27161         }
27162         
27163         this.fireEvent('footerbuttonclick', this, type);
27164     },
27165     
27166     beforeSelectFile : function(e)
27167     {
27168         e.preventDefault();
27169         
27170         if(this.fireEvent('beforeselectfile', this) != false){
27171             this.selectorEl.dom.click();
27172         }
27173     },
27174     
27175     onFileSelected : function(e)
27176     {
27177         e.preventDefault();
27178         
27179         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27180             return;
27181         }
27182         
27183         var file = this.selectorEl.dom.files[0];
27184         
27185         if(this.fireEvent('inspect', this, file) != false){
27186             this.prepare(file);
27187         }
27188         
27189     },
27190     
27191     trash : function(e)
27192     {
27193         this.fireEvent('trash', this);
27194     },
27195     
27196     download : function(e)
27197     {
27198         this.fireEvent('download', this);
27199     },
27200     
27201     loadCanvas : function(src)
27202     {   
27203         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27204             
27205             this.reset();
27206             
27207             this.imageEl = document.createElement('img');
27208             
27209             var _this = this;
27210             
27211             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27212             
27213             this.imageEl.src = src;
27214         }
27215     },
27216     
27217     onLoadCanvas : function()
27218     {   
27219         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27220         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27221         
27222         this.bodyEl.un('click', this.beforeSelectFile, this);
27223         
27224         this.notifyEl.hide();
27225         this.thumbEl.show();
27226         this.footerEl.show();
27227         
27228         this.baseRotateLevel();
27229         
27230         if(this.isDocument){
27231             this.setThumbBoxSize();
27232         }
27233         
27234         this.setThumbBoxPosition();
27235         
27236         this.baseScaleLevel();
27237         
27238         this.draw();
27239         
27240         this.resize();
27241         
27242         this.canvasLoaded = true;
27243         
27244         if(this.loadMask){
27245             this.maskEl.unmask();
27246         }
27247         
27248     },
27249     
27250     setCanvasPosition : function()
27251     {   
27252         if(!this.canvasEl){
27253             return;
27254         }
27255         
27256         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27257         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27258         
27259         this.previewEl.setLeft(pw);
27260         this.previewEl.setTop(ph);
27261         
27262     },
27263     
27264     onMouseDown : function(e)
27265     {   
27266         e.stopEvent();
27267         
27268         this.dragable = true;
27269         this.pinching = false;
27270         
27271         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27272             this.dragable = false;
27273             return;
27274         }
27275         
27276         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27277         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27278         
27279     },
27280     
27281     onMouseMove : function(e)
27282     {   
27283         e.stopEvent();
27284         
27285         if(!this.canvasLoaded){
27286             return;
27287         }
27288         
27289         if (!this.dragable){
27290             return;
27291         }
27292         
27293         var minX = Math.ceil(this.thumbEl.getLeft(true));
27294         var minY = Math.ceil(this.thumbEl.getTop(true));
27295         
27296         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27297         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27298         
27299         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27300         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27301         
27302         x = x - this.mouseX;
27303         y = y - this.mouseY;
27304         
27305         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27306         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27307         
27308         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27309         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27310         
27311         this.previewEl.setLeft(bgX);
27312         this.previewEl.setTop(bgY);
27313         
27314         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27315         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27316     },
27317     
27318     onMouseUp : function(e)
27319     {   
27320         e.stopEvent();
27321         
27322         this.dragable = false;
27323     },
27324     
27325     onMouseWheel : function(e)
27326     {   
27327         e.stopEvent();
27328         
27329         this.startScale = this.scale;
27330         
27331         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27332         
27333         if(!this.zoomable()){
27334             this.scale = this.startScale;
27335             return;
27336         }
27337         
27338         this.draw();
27339         
27340         return;
27341     },
27342     
27343     zoomable : function()
27344     {
27345         var minScale = this.thumbEl.getWidth() / this.minWidth;
27346         
27347         if(this.minWidth < this.minHeight){
27348             minScale = this.thumbEl.getHeight() / this.minHeight;
27349         }
27350         
27351         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27352         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27353         
27354         if(
27355                 this.isDocument &&
27356                 (this.rotate == 0 || this.rotate == 180) && 
27357                 (
27358                     width > this.imageEl.OriginWidth || 
27359                     height > this.imageEl.OriginHeight ||
27360                     (width < this.minWidth && height < this.minHeight)
27361                 )
27362         ){
27363             return false;
27364         }
27365         
27366         if(
27367                 this.isDocument &&
27368                 (this.rotate == 90 || this.rotate == 270) && 
27369                 (
27370                     width > this.imageEl.OriginWidth || 
27371                     height > this.imageEl.OriginHeight ||
27372                     (width < this.minHeight && height < this.minWidth)
27373                 )
27374         ){
27375             return false;
27376         }
27377         
27378         if(
27379                 !this.isDocument &&
27380                 (this.rotate == 0 || this.rotate == 180) && 
27381                 (
27382                     width < this.minWidth || 
27383                     width > this.imageEl.OriginWidth || 
27384                     height < this.minHeight || 
27385                     height > this.imageEl.OriginHeight
27386                 )
27387         ){
27388             return false;
27389         }
27390         
27391         if(
27392                 !this.isDocument &&
27393                 (this.rotate == 90 || this.rotate == 270) && 
27394                 (
27395                     width < this.minHeight || 
27396                     width > this.imageEl.OriginWidth || 
27397                     height < this.minWidth || 
27398                     height > this.imageEl.OriginHeight
27399                 )
27400         ){
27401             return false;
27402         }
27403         
27404         return true;
27405         
27406     },
27407     
27408     onRotateLeft : function(e)
27409     {   
27410         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27411             
27412             var minScale = this.thumbEl.getWidth() / this.minWidth;
27413             
27414             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27415             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27416             
27417             this.startScale = this.scale;
27418             
27419             while (this.getScaleLevel() < minScale){
27420             
27421                 this.scale = this.scale + 1;
27422                 
27423                 if(!this.zoomable()){
27424                     break;
27425                 }
27426                 
27427                 if(
27428                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27429                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27430                 ){
27431                     continue;
27432                 }
27433                 
27434                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27435
27436                 this.draw();
27437                 
27438                 return;
27439             }
27440             
27441             this.scale = this.startScale;
27442             
27443             this.onRotateFail();
27444             
27445             return false;
27446         }
27447         
27448         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27449
27450         if(this.isDocument){
27451             this.setThumbBoxSize();
27452             this.setThumbBoxPosition();
27453             this.setCanvasPosition();
27454         }
27455         
27456         this.draw();
27457         
27458         this.fireEvent('rotate', this, 'left');
27459         
27460     },
27461     
27462     onRotateRight : function(e)
27463     {
27464         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27465             
27466             var minScale = this.thumbEl.getWidth() / this.minWidth;
27467         
27468             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27469             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27470             
27471             this.startScale = this.scale;
27472             
27473             while (this.getScaleLevel() < minScale){
27474             
27475                 this.scale = this.scale + 1;
27476                 
27477                 if(!this.zoomable()){
27478                     break;
27479                 }
27480                 
27481                 if(
27482                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27483                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27484                 ){
27485                     continue;
27486                 }
27487                 
27488                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27489
27490                 this.draw();
27491                 
27492                 return;
27493             }
27494             
27495             this.scale = this.startScale;
27496             
27497             this.onRotateFail();
27498             
27499             return false;
27500         }
27501         
27502         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27503
27504         if(this.isDocument){
27505             this.setThumbBoxSize();
27506             this.setThumbBoxPosition();
27507             this.setCanvasPosition();
27508         }
27509         
27510         this.draw();
27511         
27512         this.fireEvent('rotate', this, 'right');
27513     },
27514     
27515     onRotateFail : function()
27516     {
27517         this.errorEl.show(true);
27518         
27519         var _this = this;
27520         
27521         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27522     },
27523     
27524     draw : function()
27525     {
27526         this.previewEl.dom.innerHTML = '';
27527         
27528         var canvasEl = document.createElement("canvas");
27529         
27530         var contextEl = canvasEl.getContext("2d");
27531         
27532         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27533         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27534         var center = this.imageEl.OriginWidth / 2;
27535         
27536         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27537             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27538             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27539             center = this.imageEl.OriginHeight / 2;
27540         }
27541         
27542         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27543         
27544         contextEl.translate(center, center);
27545         contextEl.rotate(this.rotate * Math.PI / 180);
27546
27547         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27548         
27549         this.canvasEl = document.createElement("canvas");
27550         
27551         this.contextEl = this.canvasEl.getContext("2d");
27552         
27553         switch (this.rotate) {
27554             case 0 :
27555                 
27556                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27557                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27558                 
27559                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27560                 
27561                 break;
27562             case 90 : 
27563                 
27564                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27565                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27566                 
27567                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27568                     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);
27569                     break;
27570                 }
27571                 
27572                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27573                 
27574                 break;
27575             case 180 :
27576                 
27577                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27578                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27579                 
27580                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27581                     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);
27582                     break;
27583                 }
27584                 
27585                 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);
27586                 
27587                 break;
27588             case 270 :
27589                 
27590                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27591                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27592         
27593                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27594                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27595                     break;
27596                 }
27597                 
27598                 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);
27599                 
27600                 break;
27601             default : 
27602                 break;
27603         }
27604         
27605         this.previewEl.appendChild(this.canvasEl);
27606         
27607         this.setCanvasPosition();
27608     },
27609     
27610     crop : function()
27611     {
27612         if(!this.canvasLoaded){
27613             return;
27614         }
27615         
27616         var imageCanvas = document.createElement("canvas");
27617         
27618         var imageContext = imageCanvas.getContext("2d");
27619         
27620         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27621         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27622         
27623         var center = imageCanvas.width / 2;
27624         
27625         imageContext.translate(center, center);
27626         
27627         imageContext.rotate(this.rotate * Math.PI / 180);
27628         
27629         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27630         
27631         var canvas = document.createElement("canvas");
27632         
27633         var context = canvas.getContext("2d");
27634                 
27635         canvas.width = this.minWidth;
27636         canvas.height = this.minHeight;
27637
27638         switch (this.rotate) {
27639             case 0 :
27640                 
27641                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27642                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27643                 
27644                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27645                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27646                 
27647                 var targetWidth = this.minWidth - 2 * x;
27648                 var targetHeight = this.minHeight - 2 * y;
27649                 
27650                 var scale = 1;
27651                 
27652                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27653                     scale = targetWidth / width;
27654                 }
27655                 
27656                 if(x > 0 && y == 0){
27657                     scale = targetHeight / height;
27658                 }
27659                 
27660                 if(x > 0 && y > 0){
27661                     scale = targetWidth / width;
27662                     
27663                     if(width < height){
27664                         scale = targetHeight / height;
27665                     }
27666                 }
27667                 
27668                 context.scale(scale, scale);
27669                 
27670                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27671                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27672
27673                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27674                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27675
27676                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27677                 
27678                 break;
27679             case 90 : 
27680                 
27681                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27682                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27683                 
27684                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27685                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27686                 
27687                 var targetWidth = this.minWidth - 2 * x;
27688                 var targetHeight = this.minHeight - 2 * y;
27689                 
27690                 var scale = 1;
27691                 
27692                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27693                     scale = targetWidth / width;
27694                 }
27695                 
27696                 if(x > 0 && y == 0){
27697                     scale = targetHeight / height;
27698                 }
27699                 
27700                 if(x > 0 && y > 0){
27701                     scale = targetWidth / width;
27702                     
27703                     if(width < height){
27704                         scale = targetHeight / height;
27705                     }
27706                 }
27707                 
27708                 context.scale(scale, scale);
27709                 
27710                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27711                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27712
27713                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27714                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27715                 
27716                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27717                 
27718                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27719                 
27720                 break;
27721             case 180 :
27722                 
27723                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27724                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27725                 
27726                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27727                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27728                 
27729                 var targetWidth = this.minWidth - 2 * x;
27730                 var targetHeight = this.minHeight - 2 * y;
27731                 
27732                 var scale = 1;
27733                 
27734                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27735                     scale = targetWidth / width;
27736                 }
27737                 
27738                 if(x > 0 && y == 0){
27739                     scale = targetHeight / height;
27740                 }
27741                 
27742                 if(x > 0 && y > 0){
27743                     scale = targetWidth / width;
27744                     
27745                     if(width < height){
27746                         scale = targetHeight / height;
27747                     }
27748                 }
27749                 
27750                 context.scale(scale, scale);
27751                 
27752                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27753                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27754
27755                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27756                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27757
27758                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27759                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27760                 
27761                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27762                 
27763                 break;
27764             case 270 :
27765                 
27766                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27767                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27768                 
27769                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27770                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27771                 
27772                 var targetWidth = this.minWidth - 2 * x;
27773                 var targetHeight = this.minHeight - 2 * y;
27774                 
27775                 var scale = 1;
27776                 
27777                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27778                     scale = targetWidth / width;
27779                 }
27780                 
27781                 if(x > 0 && y == 0){
27782                     scale = targetHeight / height;
27783                 }
27784                 
27785                 if(x > 0 && y > 0){
27786                     scale = targetWidth / width;
27787                     
27788                     if(width < height){
27789                         scale = targetHeight / height;
27790                     }
27791                 }
27792                 
27793                 context.scale(scale, scale);
27794                 
27795                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27796                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27797
27798                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27799                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27800                 
27801                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27802                 
27803                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27804                 
27805                 break;
27806             default : 
27807                 break;
27808         }
27809         
27810         this.cropData = canvas.toDataURL(this.cropType);
27811         
27812         if(this.fireEvent('crop', this, this.cropData) !== false){
27813             this.process(this.file, this.cropData);
27814         }
27815         
27816         return;
27817         
27818     },
27819     
27820     setThumbBoxSize : function()
27821     {
27822         var width, height;
27823         
27824         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27825             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27826             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27827             
27828             this.minWidth = width;
27829             this.minHeight = height;
27830             
27831             if(this.rotate == 90 || this.rotate == 270){
27832                 this.minWidth = height;
27833                 this.minHeight = width;
27834             }
27835         }
27836         
27837         height = 300;
27838         width = Math.ceil(this.minWidth * height / this.minHeight);
27839         
27840         if(this.minWidth > this.minHeight){
27841             width = 300;
27842             height = Math.ceil(this.minHeight * width / this.minWidth);
27843         }
27844         
27845         this.thumbEl.setStyle({
27846             width : width + 'px',
27847             height : height + 'px'
27848         });
27849
27850         return;
27851             
27852     },
27853     
27854     setThumbBoxPosition : function()
27855     {
27856         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27857         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27858         
27859         this.thumbEl.setLeft(x);
27860         this.thumbEl.setTop(y);
27861         
27862     },
27863     
27864     baseRotateLevel : function()
27865     {
27866         this.baseRotate = 1;
27867         
27868         if(
27869                 typeof(this.exif) != 'undefined' &&
27870                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27871                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27872         ){
27873             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27874         }
27875         
27876         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27877         
27878     },
27879     
27880     baseScaleLevel : function()
27881     {
27882         var width, height;
27883         
27884         if(this.isDocument){
27885             
27886             if(this.baseRotate == 6 || this.baseRotate == 8){
27887             
27888                 height = this.thumbEl.getHeight();
27889                 this.baseScale = height / this.imageEl.OriginWidth;
27890
27891                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27892                     width = this.thumbEl.getWidth();
27893                     this.baseScale = width / this.imageEl.OriginHeight;
27894                 }
27895
27896                 return;
27897             }
27898
27899             height = this.thumbEl.getHeight();
27900             this.baseScale = height / this.imageEl.OriginHeight;
27901
27902             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27903                 width = this.thumbEl.getWidth();
27904                 this.baseScale = width / this.imageEl.OriginWidth;
27905             }
27906
27907             return;
27908         }
27909         
27910         if(this.baseRotate == 6 || this.baseRotate == 8){
27911             
27912             width = this.thumbEl.getHeight();
27913             this.baseScale = width / this.imageEl.OriginHeight;
27914             
27915             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27916                 height = this.thumbEl.getWidth();
27917                 this.baseScale = height / this.imageEl.OriginHeight;
27918             }
27919             
27920             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27921                 height = this.thumbEl.getWidth();
27922                 this.baseScale = height / this.imageEl.OriginHeight;
27923                 
27924                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27925                     width = this.thumbEl.getHeight();
27926                     this.baseScale = width / this.imageEl.OriginWidth;
27927                 }
27928             }
27929             
27930             return;
27931         }
27932         
27933         width = this.thumbEl.getWidth();
27934         this.baseScale = width / this.imageEl.OriginWidth;
27935         
27936         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27937             height = this.thumbEl.getHeight();
27938             this.baseScale = height / this.imageEl.OriginHeight;
27939         }
27940         
27941         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27942             
27943             height = this.thumbEl.getHeight();
27944             this.baseScale = height / this.imageEl.OriginHeight;
27945             
27946             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27947                 width = this.thumbEl.getWidth();
27948                 this.baseScale = width / this.imageEl.OriginWidth;
27949             }
27950             
27951         }
27952         
27953         return;
27954     },
27955     
27956     getScaleLevel : function()
27957     {
27958         return this.baseScale * Math.pow(1.1, this.scale);
27959     },
27960     
27961     onTouchStart : function(e)
27962     {
27963         if(!this.canvasLoaded){
27964             this.beforeSelectFile(e);
27965             return;
27966         }
27967         
27968         var touches = e.browserEvent.touches;
27969         
27970         if(!touches){
27971             return;
27972         }
27973         
27974         if(touches.length == 1){
27975             this.onMouseDown(e);
27976             return;
27977         }
27978         
27979         if(touches.length != 2){
27980             return;
27981         }
27982         
27983         var coords = [];
27984         
27985         for(var i = 0, finger; finger = touches[i]; i++){
27986             coords.push(finger.pageX, finger.pageY);
27987         }
27988         
27989         var x = Math.pow(coords[0] - coords[2], 2);
27990         var y = Math.pow(coords[1] - coords[3], 2);
27991         
27992         this.startDistance = Math.sqrt(x + y);
27993         
27994         this.startScale = this.scale;
27995         
27996         this.pinching = true;
27997         this.dragable = false;
27998         
27999     },
28000     
28001     onTouchMove : function(e)
28002     {
28003         if(!this.pinching && !this.dragable){
28004             return;
28005         }
28006         
28007         var touches = e.browserEvent.touches;
28008         
28009         if(!touches){
28010             return;
28011         }
28012         
28013         if(this.dragable){
28014             this.onMouseMove(e);
28015             return;
28016         }
28017         
28018         var coords = [];
28019         
28020         for(var i = 0, finger; finger = touches[i]; i++){
28021             coords.push(finger.pageX, finger.pageY);
28022         }
28023         
28024         var x = Math.pow(coords[0] - coords[2], 2);
28025         var y = Math.pow(coords[1] - coords[3], 2);
28026         
28027         this.endDistance = Math.sqrt(x + y);
28028         
28029         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28030         
28031         if(!this.zoomable()){
28032             this.scale = this.startScale;
28033             return;
28034         }
28035         
28036         this.draw();
28037         
28038     },
28039     
28040     onTouchEnd : function(e)
28041     {
28042         this.pinching = false;
28043         this.dragable = false;
28044         
28045     },
28046     
28047     process : function(file, crop)
28048     {
28049         if(this.loadMask){
28050             this.maskEl.mask(this.loadingText);
28051         }
28052         
28053         this.xhr = new XMLHttpRequest();
28054         
28055         file.xhr = this.xhr;
28056
28057         this.xhr.open(this.method, this.url, true);
28058         
28059         var headers = {
28060             "Accept": "application/json",
28061             "Cache-Control": "no-cache",
28062             "X-Requested-With": "XMLHttpRequest"
28063         };
28064         
28065         for (var headerName in headers) {
28066             var headerValue = headers[headerName];
28067             if (headerValue) {
28068                 this.xhr.setRequestHeader(headerName, headerValue);
28069             }
28070         }
28071         
28072         var _this = this;
28073         
28074         this.xhr.onload = function()
28075         {
28076             _this.xhrOnLoad(_this.xhr);
28077         }
28078         
28079         this.xhr.onerror = function()
28080         {
28081             _this.xhrOnError(_this.xhr);
28082         }
28083         
28084         var formData = new FormData();
28085
28086         formData.append('returnHTML', 'NO');
28087         
28088         if(crop){
28089             formData.append('crop', crop);
28090         }
28091         
28092         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28093             formData.append(this.paramName, file, file.name);
28094         }
28095         
28096         if(typeof(file.filename) != 'undefined'){
28097             formData.append('filename', file.filename);
28098         }
28099         
28100         if(typeof(file.mimetype) != 'undefined'){
28101             formData.append('mimetype', file.mimetype);
28102         }
28103         
28104         if(this.fireEvent('arrange', this, formData) != false){
28105             this.xhr.send(formData);
28106         };
28107     },
28108     
28109     xhrOnLoad : function(xhr)
28110     {
28111         if(this.loadMask){
28112             this.maskEl.unmask();
28113         }
28114         
28115         if (xhr.readyState !== 4) {
28116             this.fireEvent('exception', this, xhr);
28117             return;
28118         }
28119
28120         var response = Roo.decode(xhr.responseText);
28121         
28122         if(!response.success){
28123             this.fireEvent('exception', this, xhr);
28124             return;
28125         }
28126         
28127         var response = Roo.decode(xhr.responseText);
28128         
28129         this.fireEvent('upload', this, response);
28130         
28131     },
28132     
28133     xhrOnError : function()
28134     {
28135         if(this.loadMask){
28136             this.maskEl.unmask();
28137         }
28138         
28139         Roo.log('xhr on error');
28140         
28141         var response = Roo.decode(xhr.responseText);
28142           
28143         Roo.log(response);
28144         
28145     },
28146     
28147     prepare : function(file)
28148     {   
28149         if(this.loadMask){
28150             this.maskEl.mask(this.loadingText);
28151         }
28152         
28153         this.file = false;
28154         this.exif = {};
28155         
28156         if(typeof(file) === 'string'){
28157             this.loadCanvas(file);
28158             return;
28159         }
28160         
28161         if(!file || !this.urlAPI){
28162             return;
28163         }
28164         
28165         this.file = file;
28166         this.cropType = file.type;
28167         
28168         var _this = this;
28169         
28170         if(this.fireEvent('prepare', this, this.file) != false){
28171             
28172             var reader = new FileReader();
28173             
28174             reader.onload = function (e) {
28175                 if (e.target.error) {
28176                     Roo.log(e.target.error);
28177                     return;
28178                 }
28179                 
28180                 var buffer = e.target.result,
28181                     dataView = new DataView(buffer),
28182                     offset = 2,
28183                     maxOffset = dataView.byteLength - 4,
28184                     markerBytes,
28185                     markerLength;
28186                 
28187                 if (dataView.getUint16(0) === 0xffd8) {
28188                     while (offset < maxOffset) {
28189                         markerBytes = dataView.getUint16(offset);
28190                         
28191                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28192                             markerLength = dataView.getUint16(offset + 2) + 2;
28193                             if (offset + markerLength > dataView.byteLength) {
28194                                 Roo.log('Invalid meta data: Invalid segment size.');
28195                                 break;
28196                             }
28197                             
28198                             if(markerBytes == 0xffe1){
28199                                 _this.parseExifData(
28200                                     dataView,
28201                                     offset,
28202                                     markerLength
28203                                 );
28204                             }
28205                             
28206                             offset += markerLength;
28207                             
28208                             continue;
28209                         }
28210                         
28211                         break;
28212                     }
28213                     
28214                 }
28215                 
28216                 var url = _this.urlAPI.createObjectURL(_this.file);
28217                 
28218                 _this.loadCanvas(url);
28219                 
28220                 return;
28221             }
28222             
28223             reader.readAsArrayBuffer(this.file);
28224             
28225         }
28226         
28227     },
28228     
28229     parseExifData : function(dataView, offset, length)
28230     {
28231         var tiffOffset = offset + 10,
28232             littleEndian,
28233             dirOffset;
28234     
28235         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28236             // No Exif data, might be XMP data instead
28237             return;
28238         }
28239         
28240         // Check for the ASCII code for "Exif" (0x45786966):
28241         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28242             // No Exif data, might be XMP data instead
28243             return;
28244         }
28245         if (tiffOffset + 8 > dataView.byteLength) {
28246             Roo.log('Invalid Exif data: Invalid segment size.');
28247             return;
28248         }
28249         // Check for the two null bytes:
28250         if (dataView.getUint16(offset + 8) !== 0x0000) {
28251             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28252             return;
28253         }
28254         // Check the byte alignment:
28255         switch (dataView.getUint16(tiffOffset)) {
28256         case 0x4949:
28257             littleEndian = true;
28258             break;
28259         case 0x4D4D:
28260             littleEndian = false;
28261             break;
28262         default:
28263             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28264             return;
28265         }
28266         // Check for the TIFF tag marker (0x002A):
28267         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28268             Roo.log('Invalid Exif data: Missing TIFF marker.');
28269             return;
28270         }
28271         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28272         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28273         
28274         this.parseExifTags(
28275             dataView,
28276             tiffOffset,
28277             tiffOffset + dirOffset,
28278             littleEndian
28279         );
28280     },
28281     
28282     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28283     {
28284         var tagsNumber,
28285             dirEndOffset,
28286             i;
28287         if (dirOffset + 6 > dataView.byteLength) {
28288             Roo.log('Invalid Exif data: Invalid directory offset.');
28289             return;
28290         }
28291         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28292         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28293         if (dirEndOffset + 4 > dataView.byteLength) {
28294             Roo.log('Invalid Exif data: Invalid directory size.');
28295             return;
28296         }
28297         for (i = 0; i < tagsNumber; i += 1) {
28298             this.parseExifTag(
28299                 dataView,
28300                 tiffOffset,
28301                 dirOffset + 2 + 12 * i, // tag offset
28302                 littleEndian
28303             );
28304         }
28305         // Return the offset to the next directory:
28306         return dataView.getUint32(dirEndOffset, littleEndian);
28307     },
28308     
28309     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28310     {
28311         var tag = dataView.getUint16(offset, littleEndian);
28312         
28313         this.exif[tag] = this.getExifValue(
28314             dataView,
28315             tiffOffset,
28316             offset,
28317             dataView.getUint16(offset + 2, littleEndian), // tag type
28318             dataView.getUint32(offset + 4, littleEndian), // tag length
28319             littleEndian
28320         );
28321     },
28322     
28323     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28324     {
28325         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28326             tagSize,
28327             dataOffset,
28328             values,
28329             i,
28330             str,
28331             c;
28332     
28333         if (!tagType) {
28334             Roo.log('Invalid Exif data: Invalid tag type.');
28335             return;
28336         }
28337         
28338         tagSize = tagType.size * length;
28339         // Determine if the value is contained in the dataOffset bytes,
28340         // or if the value at the dataOffset is a pointer to the actual data:
28341         dataOffset = tagSize > 4 ?
28342                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28343         if (dataOffset + tagSize > dataView.byteLength) {
28344             Roo.log('Invalid Exif data: Invalid data offset.');
28345             return;
28346         }
28347         if (length === 1) {
28348             return tagType.getValue(dataView, dataOffset, littleEndian);
28349         }
28350         values = [];
28351         for (i = 0; i < length; i += 1) {
28352             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28353         }
28354         
28355         if (tagType.ascii) {
28356             str = '';
28357             // Concatenate the chars:
28358             for (i = 0; i < values.length; i += 1) {
28359                 c = values[i];
28360                 // Ignore the terminating NULL byte(s):
28361                 if (c === '\u0000') {
28362                     break;
28363                 }
28364                 str += c;
28365             }
28366             return str;
28367         }
28368         return values;
28369     }
28370     
28371 });
28372
28373 Roo.apply(Roo.bootstrap.UploadCropbox, {
28374     tags : {
28375         'Orientation': 0x0112
28376     },
28377     
28378     Orientation: {
28379             1: 0, //'top-left',
28380 //            2: 'top-right',
28381             3: 180, //'bottom-right',
28382 //            4: 'bottom-left',
28383 //            5: 'left-top',
28384             6: 90, //'right-top',
28385 //            7: 'right-bottom',
28386             8: 270 //'left-bottom'
28387     },
28388     
28389     exifTagTypes : {
28390         // byte, 8-bit unsigned int:
28391         1: {
28392             getValue: function (dataView, dataOffset) {
28393                 return dataView.getUint8(dataOffset);
28394             },
28395             size: 1
28396         },
28397         // ascii, 8-bit byte:
28398         2: {
28399             getValue: function (dataView, dataOffset) {
28400                 return String.fromCharCode(dataView.getUint8(dataOffset));
28401             },
28402             size: 1,
28403             ascii: true
28404         },
28405         // short, 16 bit int:
28406         3: {
28407             getValue: function (dataView, dataOffset, littleEndian) {
28408                 return dataView.getUint16(dataOffset, littleEndian);
28409             },
28410             size: 2
28411         },
28412         // long, 32 bit int:
28413         4: {
28414             getValue: function (dataView, dataOffset, littleEndian) {
28415                 return dataView.getUint32(dataOffset, littleEndian);
28416             },
28417             size: 4
28418         },
28419         // rational = two long values, first is numerator, second is denominator:
28420         5: {
28421             getValue: function (dataView, dataOffset, littleEndian) {
28422                 return dataView.getUint32(dataOffset, littleEndian) /
28423                     dataView.getUint32(dataOffset + 4, littleEndian);
28424             },
28425             size: 8
28426         },
28427         // slong, 32 bit signed int:
28428         9: {
28429             getValue: function (dataView, dataOffset, littleEndian) {
28430                 return dataView.getInt32(dataOffset, littleEndian);
28431             },
28432             size: 4
28433         },
28434         // srational, two slongs, first is numerator, second is denominator:
28435         10: {
28436             getValue: function (dataView, dataOffset, littleEndian) {
28437                 return dataView.getInt32(dataOffset, littleEndian) /
28438                     dataView.getInt32(dataOffset + 4, littleEndian);
28439             },
28440             size: 8
28441         }
28442     },
28443     
28444     footer : {
28445         STANDARD : [
28446             {
28447                 tag : 'div',
28448                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28449                 action : 'rotate-left',
28450                 cn : [
28451                     {
28452                         tag : 'button',
28453                         cls : 'btn btn-default',
28454                         html : '<i class="fa fa-undo"></i>'
28455                     }
28456                 ]
28457             },
28458             {
28459                 tag : 'div',
28460                 cls : 'btn-group roo-upload-cropbox-picture',
28461                 action : 'picture',
28462                 cn : [
28463                     {
28464                         tag : 'button',
28465                         cls : 'btn btn-default',
28466                         html : '<i class="fa fa-picture-o"></i>'
28467                     }
28468                 ]
28469             },
28470             {
28471                 tag : 'div',
28472                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28473                 action : 'rotate-right',
28474                 cn : [
28475                     {
28476                         tag : 'button',
28477                         cls : 'btn btn-default',
28478                         html : '<i class="fa fa-repeat"></i>'
28479                     }
28480                 ]
28481             }
28482         ],
28483         DOCUMENT : [
28484             {
28485                 tag : 'div',
28486                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28487                 action : 'rotate-left',
28488                 cn : [
28489                     {
28490                         tag : 'button',
28491                         cls : 'btn btn-default',
28492                         html : '<i class="fa fa-undo"></i>'
28493                     }
28494                 ]
28495             },
28496             {
28497                 tag : 'div',
28498                 cls : 'btn-group roo-upload-cropbox-download',
28499                 action : 'download',
28500                 cn : [
28501                     {
28502                         tag : 'button',
28503                         cls : 'btn btn-default',
28504                         html : '<i class="fa fa-download"></i>'
28505                     }
28506                 ]
28507             },
28508             {
28509                 tag : 'div',
28510                 cls : 'btn-group roo-upload-cropbox-crop',
28511                 action : 'crop',
28512                 cn : [
28513                     {
28514                         tag : 'button',
28515                         cls : 'btn btn-default',
28516                         html : '<i class="fa fa-crop"></i>'
28517                     }
28518                 ]
28519             },
28520             {
28521                 tag : 'div',
28522                 cls : 'btn-group roo-upload-cropbox-trash',
28523                 action : 'trash',
28524                 cn : [
28525                     {
28526                         tag : 'button',
28527                         cls : 'btn btn-default',
28528                         html : '<i class="fa fa-trash"></i>'
28529                     }
28530                 ]
28531             },
28532             {
28533                 tag : 'div',
28534                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28535                 action : 'rotate-right',
28536                 cn : [
28537                     {
28538                         tag : 'button',
28539                         cls : 'btn btn-default',
28540                         html : '<i class="fa fa-repeat"></i>'
28541                     }
28542                 ]
28543             }
28544         ],
28545         ROTATOR : [
28546             {
28547                 tag : 'div',
28548                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28549                 action : 'rotate-left',
28550                 cn : [
28551                     {
28552                         tag : 'button',
28553                         cls : 'btn btn-default',
28554                         html : '<i class="fa fa-undo"></i>'
28555                     }
28556                 ]
28557             },
28558             {
28559                 tag : 'div',
28560                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28561                 action : 'rotate-right',
28562                 cn : [
28563                     {
28564                         tag : 'button',
28565                         cls : 'btn btn-default',
28566                         html : '<i class="fa fa-repeat"></i>'
28567                     }
28568                 ]
28569             }
28570         ]
28571     }
28572 });
28573
28574 /*
28575 * Licence: LGPL
28576 */
28577
28578 /**
28579  * @class Roo.bootstrap.DocumentManager
28580  * @extends Roo.bootstrap.Component
28581  * Bootstrap DocumentManager class
28582  * @cfg {String} paramName default 'imageUpload'
28583  * @cfg {String} toolTipName default 'filename'
28584  * @cfg {String} method default POST
28585  * @cfg {String} url action url
28586  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28587  * @cfg {Boolean} multiple multiple upload default true
28588  * @cfg {Number} thumbSize default 300
28589  * @cfg {String} fieldLabel
28590  * @cfg {Number} labelWidth default 4
28591  * @cfg {String} labelAlign (left|top) default left
28592  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28593 * @cfg {Number} labellg set the width of label (1-12)
28594  * @cfg {Number} labelmd set the width of label (1-12)
28595  * @cfg {Number} labelsm set the width of label (1-12)
28596  * @cfg {Number} labelxs set the width of label (1-12)
28597  * 
28598  * @constructor
28599  * Create a new DocumentManager
28600  * @param {Object} config The config object
28601  */
28602
28603 Roo.bootstrap.DocumentManager = function(config){
28604     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28605     
28606     this.files = [];
28607     this.delegates = [];
28608     
28609     this.addEvents({
28610         /**
28611          * @event initial
28612          * Fire when initial the DocumentManager
28613          * @param {Roo.bootstrap.DocumentManager} this
28614          */
28615         "initial" : true,
28616         /**
28617          * @event inspect
28618          * inspect selected file
28619          * @param {Roo.bootstrap.DocumentManager} this
28620          * @param {File} file
28621          */
28622         "inspect" : true,
28623         /**
28624          * @event exception
28625          * Fire when xhr load exception
28626          * @param {Roo.bootstrap.DocumentManager} this
28627          * @param {XMLHttpRequest} xhr
28628          */
28629         "exception" : true,
28630         /**
28631          * @event afterupload
28632          * Fire when xhr load exception
28633          * @param {Roo.bootstrap.DocumentManager} this
28634          * @param {XMLHttpRequest} xhr
28635          */
28636         "afterupload" : true,
28637         /**
28638          * @event prepare
28639          * prepare the form data
28640          * @param {Roo.bootstrap.DocumentManager} this
28641          * @param {Object} formData
28642          */
28643         "prepare" : true,
28644         /**
28645          * @event remove
28646          * Fire when remove the file
28647          * @param {Roo.bootstrap.DocumentManager} this
28648          * @param {Object} file
28649          */
28650         "remove" : true,
28651         /**
28652          * @event refresh
28653          * Fire after refresh the file
28654          * @param {Roo.bootstrap.DocumentManager} this
28655          */
28656         "refresh" : true,
28657         /**
28658          * @event click
28659          * Fire after click the image
28660          * @param {Roo.bootstrap.DocumentManager} this
28661          * @param {Object} file
28662          */
28663         "click" : true,
28664         /**
28665          * @event edit
28666          * Fire when upload a image and editable set to true
28667          * @param {Roo.bootstrap.DocumentManager} this
28668          * @param {Object} file
28669          */
28670         "edit" : true,
28671         /**
28672          * @event beforeselectfile
28673          * Fire before select file
28674          * @param {Roo.bootstrap.DocumentManager} this
28675          */
28676         "beforeselectfile" : true,
28677         /**
28678          * @event process
28679          * Fire before process file
28680          * @param {Roo.bootstrap.DocumentManager} this
28681          * @param {Object} file
28682          */
28683         "process" : true,
28684         /**
28685          * @event previewrendered
28686          * Fire when preview rendered
28687          * @param {Roo.bootstrap.DocumentManager} this
28688          * @param {Object} file
28689          */
28690         "previewrendered" : true,
28691         /**
28692          */
28693         "previewResize" : true
28694         
28695     });
28696 };
28697
28698 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28699     
28700     boxes : 0,
28701     inputName : '',
28702     thumbSize : 300,
28703     multiple : true,
28704     files : false,
28705     method : 'POST',
28706     url : '',
28707     paramName : 'imageUpload',
28708     toolTipName : 'filename',
28709     fieldLabel : '',
28710     labelWidth : 4,
28711     labelAlign : 'left',
28712     editable : true,
28713     delegates : false,
28714     xhr : false, 
28715     
28716     labellg : 0,
28717     labelmd : 0,
28718     labelsm : 0,
28719     labelxs : 0,
28720     
28721     getAutoCreate : function()
28722     {   
28723         var managerWidget = {
28724             tag : 'div',
28725             cls : 'roo-document-manager',
28726             cn : [
28727                 {
28728                     tag : 'input',
28729                     cls : 'roo-document-manager-selector',
28730                     type : 'file'
28731                 },
28732                 {
28733                     tag : 'div',
28734                     cls : 'roo-document-manager-uploader',
28735                     cn : [
28736                         {
28737                             tag : 'div',
28738                             cls : 'roo-document-manager-upload-btn',
28739                             html : '<i class="fa fa-plus"></i>'
28740                         }
28741                     ]
28742                     
28743                 }
28744             ]
28745         };
28746         
28747         var content = [
28748             {
28749                 tag : 'div',
28750                 cls : 'column col-md-12',
28751                 cn : managerWidget
28752             }
28753         ];
28754         
28755         if(this.fieldLabel.length){
28756             
28757             content = [
28758                 {
28759                     tag : 'div',
28760                     cls : 'column col-md-12',
28761                     html : this.fieldLabel
28762                 },
28763                 {
28764                     tag : 'div',
28765                     cls : 'column col-md-12',
28766                     cn : managerWidget
28767                 }
28768             ];
28769
28770             if(this.labelAlign == 'left'){
28771                 content = [
28772                     {
28773                         tag : 'div',
28774                         cls : 'column',
28775                         html : this.fieldLabel
28776                     },
28777                     {
28778                         tag : 'div',
28779                         cls : 'column',
28780                         cn : managerWidget
28781                     }
28782                 ];
28783                 
28784                 if(this.labelWidth > 12){
28785                     content[0].style = "width: " + this.labelWidth + 'px';
28786                 }
28787
28788                 if(this.labelWidth < 13 && this.labelmd == 0){
28789                     this.labelmd = this.labelWidth;
28790                 }
28791
28792                 if(this.labellg > 0){
28793                     content[0].cls += ' col-lg-' + this.labellg;
28794                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28795                 }
28796
28797                 if(this.labelmd > 0){
28798                     content[0].cls += ' col-md-' + this.labelmd;
28799                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28800                 }
28801
28802                 if(this.labelsm > 0){
28803                     content[0].cls += ' col-sm-' + this.labelsm;
28804                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28805                 }
28806
28807                 if(this.labelxs > 0){
28808                     content[0].cls += ' col-xs-' + this.labelxs;
28809                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28810                 }
28811                 
28812             }
28813         }
28814         
28815         var cfg = {
28816             tag : 'div',
28817             cls : 'row clearfix',
28818             cn : content
28819         };
28820         
28821         return cfg;
28822         
28823     },
28824     
28825     initEvents : function()
28826     {
28827         this.managerEl = this.el.select('.roo-document-manager', true).first();
28828         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28829         
28830         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28831         this.selectorEl.hide();
28832         
28833         if(this.multiple){
28834             this.selectorEl.attr('multiple', 'multiple');
28835         }
28836         
28837         this.selectorEl.on('change', this.onFileSelected, this);
28838         
28839         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28840         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28841         
28842         this.uploader.on('click', this.onUploaderClick, this);
28843         
28844         this.renderProgressDialog();
28845         
28846         var _this = this;
28847         
28848         window.addEventListener("resize", function() { _this.refresh(); } );
28849         
28850         this.fireEvent('initial', this);
28851     },
28852     
28853     renderProgressDialog : function()
28854     {
28855         var _this = this;
28856         
28857         this.progressDialog = new Roo.bootstrap.Modal({
28858             cls : 'roo-document-manager-progress-dialog',
28859             allow_close : false,
28860             title : '',
28861             buttons : [
28862                 {
28863                     name  :'cancel',
28864                     weight : 'danger',
28865                     html : 'Cancel'
28866                 }
28867             ], 
28868             listeners : { 
28869                 btnclick : function() {
28870                     _this.uploadCancel();
28871                     this.hide();
28872                 }
28873             }
28874         });
28875          
28876         this.progressDialog.render(Roo.get(document.body));
28877          
28878         this.progress = new Roo.bootstrap.Progress({
28879             cls : 'roo-document-manager-progress',
28880             active : true,
28881             striped : true
28882         });
28883         
28884         this.progress.render(this.progressDialog.getChildContainer());
28885         
28886         this.progressBar = new Roo.bootstrap.ProgressBar({
28887             cls : 'roo-document-manager-progress-bar',
28888             aria_valuenow : 0,
28889             aria_valuemin : 0,
28890             aria_valuemax : 12,
28891             panel : 'success'
28892         });
28893         
28894         this.progressBar.render(this.progress.getChildContainer());
28895     },
28896     
28897     onUploaderClick : function(e)
28898     {
28899         e.preventDefault();
28900      
28901         if(this.fireEvent('beforeselectfile', this) != false){
28902             this.selectorEl.dom.click();
28903         }
28904         
28905     },
28906     
28907     onFileSelected : function(e)
28908     {
28909         e.preventDefault();
28910         
28911         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28912             return;
28913         }
28914         
28915         Roo.each(this.selectorEl.dom.files, function(file){
28916             if(this.fireEvent('inspect', this, file) != false){
28917                 this.files.push(file);
28918             }
28919         }, this);
28920         
28921         this.queue();
28922         
28923     },
28924     
28925     queue : function()
28926     {
28927         this.selectorEl.dom.value = '';
28928         
28929         if(!this.files || !this.files.length){
28930             return;
28931         }
28932         
28933         if(this.boxes > 0 && this.files.length > this.boxes){
28934             this.files = this.files.slice(0, this.boxes);
28935         }
28936         
28937         this.uploader.show();
28938         
28939         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28940             this.uploader.hide();
28941         }
28942         
28943         var _this = this;
28944         
28945         var files = [];
28946         
28947         var docs = [];
28948         
28949         Roo.each(this.files, function(file){
28950             
28951             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28952                 var f = this.renderPreview(file);
28953                 files.push(f);
28954                 return;
28955             }
28956             
28957             if(file.type.indexOf('image') != -1){
28958                 this.delegates.push(
28959                     (function(){
28960                         _this.process(file);
28961                     }).createDelegate(this)
28962                 );
28963         
28964                 return;
28965             }
28966             
28967             docs.push(
28968                 (function(){
28969                     _this.process(file);
28970                 }).createDelegate(this)
28971             );
28972             
28973         }, this);
28974         
28975         this.files = files;
28976         
28977         this.delegates = this.delegates.concat(docs);
28978         
28979         if(!this.delegates.length){
28980             this.refresh();
28981             return;
28982         }
28983         
28984         this.progressBar.aria_valuemax = this.delegates.length;
28985         
28986         this.arrange();
28987         
28988         return;
28989     },
28990     
28991     arrange : function()
28992     {
28993         if(!this.delegates.length){
28994             this.progressDialog.hide();
28995             this.refresh();
28996             return;
28997         }
28998         
28999         var delegate = this.delegates.shift();
29000         
29001         this.progressDialog.show();
29002         
29003         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29004         
29005         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29006         
29007         delegate();
29008     },
29009     
29010     refresh : function()
29011     {
29012         this.uploader.show();
29013         
29014         if(this.boxes > 0 && this.files.length > this.boxes - 1){
29015             this.uploader.hide();
29016         }
29017         
29018         Roo.isTouch ? this.closable(false) : this.closable(true);
29019         
29020         this.fireEvent('refresh', this);
29021     },
29022     
29023     onRemove : function(e, el, o)
29024     {
29025         e.preventDefault();
29026         
29027         this.fireEvent('remove', this, o);
29028         
29029     },
29030     
29031     remove : function(o)
29032     {
29033         var files = [];
29034         
29035         Roo.each(this.files, function(file){
29036             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29037                 files.push(file);
29038                 return;
29039             }
29040
29041             o.target.remove();
29042
29043         }, this);
29044         
29045         this.files = files;
29046         
29047         this.refresh();
29048     },
29049     
29050     clear : function()
29051     {
29052         Roo.each(this.files, function(file){
29053             if(!file.target){
29054                 return;
29055             }
29056             
29057             file.target.remove();
29058
29059         }, this);
29060         
29061         this.files = [];
29062         
29063         this.refresh();
29064     },
29065     
29066     onClick : function(e, el, o)
29067     {
29068         e.preventDefault();
29069         
29070         this.fireEvent('click', this, o);
29071         
29072     },
29073     
29074     closable : function(closable)
29075     {
29076         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29077             
29078             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29079             
29080             if(closable){
29081                 el.show();
29082                 return;
29083             }
29084             
29085             el.hide();
29086             
29087         }, this);
29088     },
29089     
29090     xhrOnLoad : function(xhr)
29091     {
29092         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29093             el.remove();
29094         }, this);
29095         
29096         if (xhr.readyState !== 4) {
29097             this.arrange();
29098             this.fireEvent('exception', this, xhr);
29099             return;
29100         }
29101
29102         var response = Roo.decode(xhr.responseText);
29103         
29104         if(!response.success){
29105             this.arrange();
29106             this.fireEvent('exception', this, xhr);
29107             return;
29108         }
29109         
29110         var file = this.renderPreview(response.data);
29111         
29112         this.files.push(file);
29113         
29114         this.arrange();
29115         
29116         this.fireEvent('afterupload', this, xhr);
29117         
29118     },
29119     
29120     xhrOnError : function(xhr)
29121     {
29122         Roo.log('xhr on error');
29123         
29124         var response = Roo.decode(xhr.responseText);
29125           
29126         Roo.log(response);
29127         
29128         this.arrange();
29129     },
29130     
29131     process : function(file)
29132     {
29133         if(this.fireEvent('process', this, file) !== false){
29134             if(this.editable && file.type.indexOf('image') != -1){
29135                 this.fireEvent('edit', this, file);
29136                 return;
29137             }
29138
29139             this.uploadStart(file, false);
29140
29141             return;
29142         }
29143         
29144     },
29145     
29146     uploadStart : function(file, crop)
29147     {
29148         this.xhr = new XMLHttpRequest();
29149         
29150         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29151             this.arrange();
29152             return;
29153         }
29154         
29155         file.xhr = this.xhr;
29156             
29157         this.managerEl.createChild({
29158             tag : 'div',
29159             cls : 'roo-document-manager-loading',
29160             cn : [
29161                 {
29162                     tag : 'div',
29163                     tooltip : file.name,
29164                     cls : 'roo-document-manager-thumb',
29165                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29166                 }
29167             ]
29168
29169         });
29170
29171         this.xhr.open(this.method, this.url, true);
29172         
29173         var headers = {
29174             "Accept": "application/json",
29175             "Cache-Control": "no-cache",
29176             "X-Requested-With": "XMLHttpRequest"
29177         };
29178         
29179         for (var headerName in headers) {
29180             var headerValue = headers[headerName];
29181             if (headerValue) {
29182                 this.xhr.setRequestHeader(headerName, headerValue);
29183             }
29184         }
29185         
29186         var _this = this;
29187         
29188         this.xhr.onload = function()
29189         {
29190             _this.xhrOnLoad(_this.xhr);
29191         }
29192         
29193         this.xhr.onerror = function()
29194         {
29195             _this.xhrOnError(_this.xhr);
29196         }
29197         
29198         var formData = new FormData();
29199
29200         formData.append('returnHTML', 'NO');
29201         
29202         if(crop){
29203             formData.append('crop', crop);
29204         }
29205         
29206         formData.append(this.paramName, file, file.name);
29207         
29208         var options = {
29209             file : file, 
29210             manually : false
29211         };
29212         
29213         if(this.fireEvent('prepare', this, formData, options) != false){
29214             
29215             if(options.manually){
29216                 return;
29217             }
29218             
29219             this.xhr.send(formData);
29220             return;
29221         };
29222         
29223         this.uploadCancel();
29224     },
29225     
29226     uploadCancel : function()
29227     {
29228         if (this.xhr) {
29229             this.xhr.abort();
29230         }
29231         
29232         this.delegates = [];
29233         
29234         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29235             el.remove();
29236         }, this);
29237         
29238         this.arrange();
29239     },
29240     
29241     renderPreview : function(file)
29242     {
29243         if(typeof(file.target) != 'undefined' && file.target){
29244             return file;
29245         }
29246         
29247         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29248         
29249         var previewEl = this.managerEl.createChild({
29250             tag : 'div',
29251             cls : 'roo-document-manager-preview',
29252             cn : [
29253                 {
29254                     tag : 'div',
29255                     tooltip : file[this.toolTipName],
29256                     cls : 'roo-document-manager-thumb',
29257                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29258                 },
29259                 {
29260                     tag : 'button',
29261                     cls : 'close',
29262                     html : '<i class="fa fa-times-circle"></i>'
29263                 }
29264             ]
29265         });
29266
29267         var close = previewEl.select('button.close', true).first();
29268
29269         close.on('click', this.onRemove, this, file);
29270
29271         file.target = previewEl;
29272
29273         var image = previewEl.select('img', true).first();
29274         
29275         var _this = this;
29276         
29277         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29278         
29279         image.on('click', this.onClick, this, file);
29280         
29281         this.fireEvent('previewrendered', this, file);
29282         
29283         return file;
29284         
29285     },
29286     
29287     onPreviewLoad : function(file, image)
29288     {
29289         if(typeof(file.target) == 'undefined' || !file.target){
29290             return;
29291         }
29292         
29293         var width = image.dom.naturalWidth || image.dom.width;
29294         var height = image.dom.naturalHeight || image.dom.height;
29295         
29296         if(!this.previewResize) {
29297             return;
29298         }
29299         
29300         if(width > height){
29301             file.target.addClass('wide');
29302             return;
29303         }
29304         
29305         file.target.addClass('tall');
29306         return;
29307         
29308     },
29309     
29310     uploadFromSource : function(file, crop)
29311     {
29312         this.xhr = new XMLHttpRequest();
29313         
29314         this.managerEl.createChild({
29315             tag : 'div',
29316             cls : 'roo-document-manager-loading',
29317             cn : [
29318                 {
29319                     tag : 'div',
29320                     tooltip : file.name,
29321                     cls : 'roo-document-manager-thumb',
29322                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29323                 }
29324             ]
29325
29326         });
29327
29328         this.xhr.open(this.method, this.url, true);
29329         
29330         var headers = {
29331             "Accept": "application/json",
29332             "Cache-Control": "no-cache",
29333             "X-Requested-With": "XMLHttpRequest"
29334         };
29335         
29336         for (var headerName in headers) {
29337             var headerValue = headers[headerName];
29338             if (headerValue) {
29339                 this.xhr.setRequestHeader(headerName, headerValue);
29340             }
29341         }
29342         
29343         var _this = this;
29344         
29345         this.xhr.onload = function()
29346         {
29347             _this.xhrOnLoad(_this.xhr);
29348         }
29349         
29350         this.xhr.onerror = function()
29351         {
29352             _this.xhrOnError(_this.xhr);
29353         }
29354         
29355         var formData = new FormData();
29356
29357         formData.append('returnHTML', 'NO');
29358         
29359         formData.append('crop', crop);
29360         
29361         if(typeof(file.filename) != 'undefined'){
29362             formData.append('filename', file.filename);
29363         }
29364         
29365         if(typeof(file.mimetype) != 'undefined'){
29366             formData.append('mimetype', file.mimetype);
29367         }
29368         
29369         Roo.log(formData);
29370         
29371         if(this.fireEvent('prepare', this, formData) != false){
29372             this.xhr.send(formData);
29373         };
29374     }
29375 });
29376
29377 /*
29378 * Licence: LGPL
29379 */
29380
29381 /**
29382  * @class Roo.bootstrap.DocumentViewer
29383  * @extends Roo.bootstrap.Component
29384  * Bootstrap DocumentViewer class
29385  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29386  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29387  * 
29388  * @constructor
29389  * Create a new DocumentViewer
29390  * @param {Object} config The config object
29391  */
29392
29393 Roo.bootstrap.DocumentViewer = function(config){
29394     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29395     
29396     this.addEvents({
29397         /**
29398          * @event initial
29399          * Fire after initEvent
29400          * @param {Roo.bootstrap.DocumentViewer} this
29401          */
29402         "initial" : true,
29403         /**
29404          * @event click
29405          * Fire after click
29406          * @param {Roo.bootstrap.DocumentViewer} this
29407          */
29408         "click" : true,
29409         /**
29410          * @event download
29411          * Fire after download button
29412          * @param {Roo.bootstrap.DocumentViewer} this
29413          */
29414         "download" : true,
29415         /**
29416          * @event trash
29417          * Fire after trash button
29418          * @param {Roo.bootstrap.DocumentViewer} this
29419          */
29420         "trash" : true
29421         
29422     });
29423 };
29424
29425 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29426     
29427     showDownload : true,
29428     
29429     showTrash : true,
29430     
29431     getAutoCreate : function()
29432     {
29433         var cfg = {
29434             tag : 'div',
29435             cls : 'roo-document-viewer',
29436             cn : [
29437                 {
29438                     tag : 'div',
29439                     cls : 'roo-document-viewer-body',
29440                     cn : [
29441                         {
29442                             tag : 'div',
29443                             cls : 'roo-document-viewer-thumb',
29444                             cn : [
29445                                 {
29446                                     tag : 'img',
29447                                     cls : 'roo-document-viewer-image'
29448                                 }
29449                             ]
29450                         }
29451                     ]
29452                 },
29453                 {
29454                     tag : 'div',
29455                     cls : 'roo-document-viewer-footer',
29456                     cn : {
29457                         tag : 'div',
29458                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29459                         cn : [
29460                             {
29461                                 tag : 'div',
29462                                 cls : 'btn-group roo-document-viewer-download',
29463                                 cn : [
29464                                     {
29465                                         tag : 'button',
29466                                         cls : 'btn btn-default',
29467                                         html : '<i class="fa fa-download"></i>'
29468                                     }
29469                                 ]
29470                             },
29471                             {
29472                                 tag : 'div',
29473                                 cls : 'btn-group roo-document-viewer-trash',
29474                                 cn : [
29475                                     {
29476                                         tag : 'button',
29477                                         cls : 'btn btn-default',
29478                                         html : '<i class="fa fa-trash"></i>'
29479                                     }
29480                                 ]
29481                             }
29482                         ]
29483                     }
29484                 }
29485             ]
29486         };
29487         
29488         return cfg;
29489     },
29490     
29491     initEvents : function()
29492     {
29493         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29494         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29495         
29496         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29497         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29498         
29499         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29500         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29501         
29502         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29503         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29504         
29505         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29506         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29507         
29508         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29509         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29510         
29511         this.bodyEl.on('click', this.onClick, this);
29512         this.downloadBtn.on('click', this.onDownload, this);
29513         this.trashBtn.on('click', this.onTrash, this);
29514         
29515         this.downloadBtn.hide();
29516         this.trashBtn.hide();
29517         
29518         if(this.showDownload){
29519             this.downloadBtn.show();
29520         }
29521         
29522         if(this.showTrash){
29523             this.trashBtn.show();
29524         }
29525         
29526         if(!this.showDownload && !this.showTrash) {
29527             this.footerEl.hide();
29528         }
29529         
29530     },
29531     
29532     initial : function()
29533     {
29534         this.fireEvent('initial', this);
29535         
29536     },
29537     
29538     onClick : function(e)
29539     {
29540         e.preventDefault();
29541         
29542         this.fireEvent('click', this);
29543     },
29544     
29545     onDownload : function(e)
29546     {
29547         e.preventDefault();
29548         
29549         this.fireEvent('download', this);
29550     },
29551     
29552     onTrash : function(e)
29553     {
29554         e.preventDefault();
29555         
29556         this.fireEvent('trash', this);
29557     }
29558     
29559 });
29560 /*
29561  * - LGPL
29562  *
29563  * nav progress bar
29564  * 
29565  */
29566
29567 /**
29568  * @class Roo.bootstrap.NavProgressBar
29569  * @extends Roo.bootstrap.Component
29570  * Bootstrap NavProgressBar class
29571  * 
29572  * @constructor
29573  * Create a new nav progress bar
29574  * @param {Object} config The config object
29575  */
29576
29577 Roo.bootstrap.NavProgressBar = function(config){
29578     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29579
29580     this.bullets = this.bullets || [];
29581    
29582 //    Roo.bootstrap.NavProgressBar.register(this);
29583      this.addEvents({
29584         /**
29585              * @event changed
29586              * Fires when the active item changes
29587              * @param {Roo.bootstrap.NavProgressBar} this
29588              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29589              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29590          */
29591         'changed': true
29592      });
29593     
29594 };
29595
29596 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29597     
29598     bullets : [],
29599     barItems : [],
29600     
29601     getAutoCreate : function()
29602     {
29603         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29604         
29605         cfg = {
29606             tag : 'div',
29607             cls : 'roo-navigation-bar-group',
29608             cn : [
29609                 {
29610                     tag : 'div',
29611                     cls : 'roo-navigation-top-bar'
29612                 },
29613                 {
29614                     tag : 'div',
29615                     cls : 'roo-navigation-bullets-bar',
29616                     cn : [
29617                         {
29618                             tag : 'ul',
29619                             cls : 'roo-navigation-bar'
29620                         }
29621                     ]
29622                 },
29623                 
29624                 {
29625                     tag : 'div',
29626                     cls : 'roo-navigation-bottom-bar'
29627                 }
29628             ]
29629             
29630         };
29631         
29632         return cfg;
29633         
29634     },
29635     
29636     initEvents: function() 
29637     {
29638         
29639     },
29640     
29641     onRender : function(ct, position) 
29642     {
29643         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29644         
29645         if(this.bullets.length){
29646             Roo.each(this.bullets, function(b){
29647                this.addItem(b);
29648             }, this);
29649         }
29650         
29651         this.format();
29652         
29653     },
29654     
29655     addItem : function(cfg)
29656     {
29657         var item = new Roo.bootstrap.NavProgressItem(cfg);
29658         
29659         item.parentId = this.id;
29660         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29661         
29662         if(cfg.html){
29663             var top = new Roo.bootstrap.Element({
29664                 tag : 'div',
29665                 cls : 'roo-navigation-bar-text'
29666             });
29667             
29668             var bottom = new Roo.bootstrap.Element({
29669                 tag : 'div',
29670                 cls : 'roo-navigation-bar-text'
29671             });
29672             
29673             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29674             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29675             
29676             var topText = new Roo.bootstrap.Element({
29677                 tag : 'span',
29678                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29679             });
29680             
29681             var bottomText = new Roo.bootstrap.Element({
29682                 tag : 'span',
29683                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29684             });
29685             
29686             topText.onRender(top.el, null);
29687             bottomText.onRender(bottom.el, null);
29688             
29689             item.topEl = top;
29690             item.bottomEl = bottom;
29691         }
29692         
29693         this.barItems.push(item);
29694         
29695         return item;
29696     },
29697     
29698     getActive : function()
29699     {
29700         var active = false;
29701         
29702         Roo.each(this.barItems, function(v){
29703             
29704             if (!v.isActive()) {
29705                 return;
29706             }
29707             
29708             active = v;
29709             return false;
29710             
29711         });
29712         
29713         return active;
29714     },
29715     
29716     setActiveItem : function(item)
29717     {
29718         var prev = false;
29719         
29720         Roo.each(this.barItems, function(v){
29721             if (v.rid == item.rid) {
29722                 return ;
29723             }
29724             
29725             if (v.isActive()) {
29726                 v.setActive(false);
29727                 prev = v;
29728             }
29729         });
29730
29731         item.setActive(true);
29732         
29733         this.fireEvent('changed', this, item, prev);
29734     },
29735     
29736     getBarItem: function(rid)
29737     {
29738         var ret = false;
29739         
29740         Roo.each(this.barItems, function(e) {
29741             if (e.rid != rid) {
29742                 return;
29743             }
29744             
29745             ret =  e;
29746             return false;
29747         });
29748         
29749         return ret;
29750     },
29751     
29752     indexOfItem : function(item)
29753     {
29754         var index = false;
29755         
29756         Roo.each(this.barItems, function(v, i){
29757             
29758             if (v.rid != item.rid) {
29759                 return;
29760             }
29761             
29762             index = i;
29763             return false
29764         });
29765         
29766         return index;
29767     },
29768     
29769     setActiveNext : function()
29770     {
29771         var i = this.indexOfItem(this.getActive());
29772         
29773         if (i > this.barItems.length) {
29774             return;
29775         }
29776         
29777         this.setActiveItem(this.barItems[i+1]);
29778     },
29779     
29780     setActivePrev : function()
29781     {
29782         var i = this.indexOfItem(this.getActive());
29783         
29784         if (i  < 1) {
29785             return;
29786         }
29787         
29788         this.setActiveItem(this.barItems[i-1]);
29789     },
29790     
29791     format : function()
29792     {
29793         if(!this.barItems.length){
29794             return;
29795         }
29796      
29797         var width = 100 / this.barItems.length;
29798         
29799         Roo.each(this.barItems, function(i){
29800             i.el.setStyle('width', width + '%');
29801             i.topEl.el.setStyle('width', width + '%');
29802             i.bottomEl.el.setStyle('width', width + '%');
29803         }, this);
29804         
29805     }
29806     
29807 });
29808 /*
29809  * - LGPL
29810  *
29811  * Nav Progress Item
29812  * 
29813  */
29814
29815 /**
29816  * @class Roo.bootstrap.NavProgressItem
29817  * @extends Roo.bootstrap.Component
29818  * Bootstrap NavProgressItem class
29819  * @cfg {String} rid the reference id
29820  * @cfg {Boolean} active (true|false) Is item active default false
29821  * @cfg {Boolean} disabled (true|false) Is item active default false
29822  * @cfg {String} html
29823  * @cfg {String} position (top|bottom) text position default bottom
29824  * @cfg {String} icon show icon instead of number
29825  * 
29826  * @constructor
29827  * Create a new NavProgressItem
29828  * @param {Object} config The config object
29829  */
29830 Roo.bootstrap.NavProgressItem = function(config){
29831     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29832     this.addEvents({
29833         // raw events
29834         /**
29835          * @event click
29836          * The raw click event for the entire grid.
29837          * @param {Roo.bootstrap.NavProgressItem} this
29838          * @param {Roo.EventObject} e
29839          */
29840         "click" : true
29841     });
29842    
29843 };
29844
29845 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29846     
29847     rid : '',
29848     active : false,
29849     disabled : false,
29850     html : '',
29851     position : 'bottom',
29852     icon : false,
29853     
29854     getAutoCreate : function()
29855     {
29856         var iconCls = 'roo-navigation-bar-item-icon';
29857         
29858         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29859         
29860         var cfg = {
29861             tag: 'li',
29862             cls: 'roo-navigation-bar-item',
29863             cn : [
29864                 {
29865                     tag : 'i',
29866                     cls : iconCls
29867                 }
29868             ]
29869         };
29870         
29871         if(this.active){
29872             cfg.cls += ' active';
29873         }
29874         if(this.disabled){
29875             cfg.cls += ' disabled';
29876         }
29877         
29878         return cfg;
29879     },
29880     
29881     disable : function()
29882     {
29883         this.setDisabled(true);
29884     },
29885     
29886     enable : function()
29887     {
29888         this.setDisabled(false);
29889     },
29890     
29891     initEvents: function() 
29892     {
29893         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29894         
29895         this.iconEl.on('click', this.onClick, this);
29896     },
29897     
29898     onClick : function(e)
29899     {
29900         e.preventDefault();
29901         
29902         if(this.disabled){
29903             return;
29904         }
29905         
29906         if(this.fireEvent('click', this, e) === false){
29907             return;
29908         };
29909         
29910         this.parent().setActiveItem(this);
29911     },
29912     
29913     isActive: function () 
29914     {
29915         return this.active;
29916     },
29917     
29918     setActive : function(state)
29919     {
29920         if(this.active == state){
29921             return;
29922         }
29923         
29924         this.active = state;
29925         
29926         if (state) {
29927             this.el.addClass('active');
29928             return;
29929         }
29930         
29931         this.el.removeClass('active');
29932         
29933         return;
29934     },
29935     
29936     setDisabled : function(state)
29937     {
29938         if(this.disabled == state){
29939             return;
29940         }
29941         
29942         this.disabled = state;
29943         
29944         if (state) {
29945             this.el.addClass('disabled');
29946             return;
29947         }
29948         
29949         this.el.removeClass('disabled');
29950     },
29951     
29952     tooltipEl : function()
29953     {
29954         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29955     }
29956 });
29957  
29958
29959  /*
29960  * - LGPL
29961  *
29962  * FieldLabel
29963  * 
29964  */
29965
29966 /**
29967  * @class Roo.bootstrap.FieldLabel
29968  * @extends Roo.bootstrap.Component
29969  * Bootstrap FieldLabel class
29970  * @cfg {String} html contents of the element
29971  * @cfg {String} tag tag of the element default label
29972  * @cfg {String} cls class of the element
29973  * @cfg {String} target label target 
29974  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29975  * @cfg {String} invalidClass default "text-warning"
29976  * @cfg {String} validClass default "text-success"
29977  * @cfg {String} iconTooltip default "This field is required"
29978  * @cfg {String} indicatorpos (left|right) default left
29979  * 
29980  * @constructor
29981  * Create a new FieldLabel
29982  * @param {Object} config The config object
29983  */
29984
29985 Roo.bootstrap.FieldLabel = function(config){
29986     Roo.bootstrap.Element.superclass.constructor.call(this, config);
29987     
29988     this.addEvents({
29989             /**
29990              * @event invalid
29991              * Fires after the field has been marked as invalid.
29992              * @param {Roo.form.FieldLabel} this
29993              * @param {String} msg The validation message
29994              */
29995             invalid : true,
29996             /**
29997              * @event valid
29998              * Fires after the field has been validated with no errors.
29999              * @param {Roo.form.FieldLabel} this
30000              */
30001             valid : true
30002         });
30003 };
30004
30005 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
30006     
30007     tag: 'label',
30008     cls: '',
30009     html: '',
30010     target: '',
30011     allowBlank : true,
30012     invalidClass : 'has-warning',
30013     validClass : 'has-success',
30014     iconTooltip : 'This field is required',
30015     indicatorpos : 'left',
30016     
30017     getAutoCreate : function(){
30018         
30019         var cls = "";
30020         if (!this.allowBlank) {
30021             cls  = "visible";
30022         }
30023         
30024         var cfg = {
30025             tag : this.tag,
30026             cls : 'roo-bootstrap-field-label ' + this.cls,
30027             for : this.target,
30028             cn : [
30029                 {
30030                     tag : 'i',
30031                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30032                     tooltip : this.iconTooltip
30033                 },
30034                 {
30035                     tag : 'span',
30036                     html : this.html
30037                 }
30038             ] 
30039         };
30040         
30041         if(this.indicatorpos == 'right'){
30042             var cfg = {
30043                 tag : this.tag,
30044                 cls : 'roo-bootstrap-field-label ' + this.cls,
30045                 for : this.target,
30046                 cn : [
30047                     {
30048                         tag : 'span',
30049                         html : this.html
30050                     },
30051                     {
30052                         tag : 'i',
30053                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30054                         tooltip : this.iconTooltip
30055                     }
30056                 ] 
30057             };
30058         }
30059         
30060         return cfg;
30061     },
30062     
30063     initEvents: function() 
30064     {
30065         Roo.bootstrap.Element.superclass.initEvents.call(this);
30066         
30067         this.indicator = this.indicatorEl();
30068         
30069         if(this.indicator){
30070             this.indicator.removeClass('visible');
30071             this.indicator.addClass('invisible');
30072         }
30073         
30074         Roo.bootstrap.FieldLabel.register(this);
30075     },
30076     
30077     indicatorEl : function()
30078     {
30079         var indicator = this.el.select('i.roo-required-indicator',true).first();
30080         
30081         if(!indicator){
30082             return false;
30083         }
30084         
30085         return indicator;
30086         
30087     },
30088     
30089     /**
30090      * Mark this field as valid
30091      */
30092     markValid : function()
30093     {
30094         if(this.indicator){
30095             this.indicator.removeClass('visible');
30096             this.indicator.addClass('invisible');
30097         }
30098         
30099         this.el.removeClass(this.invalidClass);
30100         
30101         this.el.addClass(this.validClass);
30102         
30103         this.fireEvent('valid', this);
30104     },
30105     
30106     /**
30107      * Mark this field as invalid
30108      * @param {String} msg The validation message
30109      */
30110     markInvalid : function(msg)
30111     {
30112         if(this.indicator){
30113             this.indicator.removeClass('invisible');
30114             this.indicator.addClass('visible');
30115         }
30116         
30117         this.el.removeClass(this.validClass);
30118         
30119         this.el.addClass(this.invalidClass);
30120         
30121         this.fireEvent('invalid', this, msg);
30122     }
30123     
30124    
30125 });
30126
30127 Roo.apply(Roo.bootstrap.FieldLabel, {
30128     
30129     groups: {},
30130     
30131      /**
30132     * register a FieldLabel Group
30133     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30134     */
30135     register : function(label)
30136     {
30137         if(this.groups.hasOwnProperty(label.target)){
30138             return;
30139         }
30140      
30141         this.groups[label.target] = label;
30142         
30143     },
30144     /**
30145     * fetch a FieldLabel Group based on the target
30146     * @param {string} target
30147     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30148     */
30149     get: function(target) {
30150         if (typeof(this.groups[target]) == 'undefined') {
30151             return false;
30152         }
30153         
30154         return this.groups[target] ;
30155     }
30156 });
30157
30158  
30159
30160  /*
30161  * - LGPL
30162  *
30163  * page DateSplitField.
30164  * 
30165  */
30166
30167
30168 /**
30169  * @class Roo.bootstrap.DateSplitField
30170  * @extends Roo.bootstrap.Component
30171  * Bootstrap DateSplitField class
30172  * @cfg {string} fieldLabel - the label associated
30173  * @cfg {Number} labelWidth set the width of label (0-12)
30174  * @cfg {String} labelAlign (top|left)
30175  * @cfg {Boolean} dayAllowBlank (true|false) default false
30176  * @cfg {Boolean} monthAllowBlank (true|false) default false
30177  * @cfg {Boolean} yearAllowBlank (true|false) default false
30178  * @cfg {string} dayPlaceholder 
30179  * @cfg {string} monthPlaceholder
30180  * @cfg {string} yearPlaceholder
30181  * @cfg {string} dayFormat default 'd'
30182  * @cfg {string} monthFormat default 'm'
30183  * @cfg {string} yearFormat default 'Y'
30184  * @cfg {Number} labellg set the width of label (1-12)
30185  * @cfg {Number} labelmd set the width of label (1-12)
30186  * @cfg {Number} labelsm set the width of label (1-12)
30187  * @cfg {Number} labelxs set the width of label (1-12)
30188
30189  *     
30190  * @constructor
30191  * Create a new DateSplitField
30192  * @param {Object} config The config object
30193  */
30194
30195 Roo.bootstrap.DateSplitField = function(config){
30196     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30197     
30198     this.addEvents({
30199         // raw events
30200          /**
30201          * @event years
30202          * getting the data of years
30203          * @param {Roo.bootstrap.DateSplitField} this
30204          * @param {Object} years
30205          */
30206         "years" : true,
30207         /**
30208          * @event days
30209          * getting the data of days
30210          * @param {Roo.bootstrap.DateSplitField} this
30211          * @param {Object} days
30212          */
30213         "days" : true,
30214         /**
30215          * @event invalid
30216          * Fires after the field has been marked as invalid.
30217          * @param {Roo.form.Field} this
30218          * @param {String} msg The validation message
30219          */
30220         invalid : true,
30221        /**
30222          * @event valid
30223          * Fires after the field has been validated with no errors.
30224          * @param {Roo.form.Field} this
30225          */
30226         valid : true
30227     });
30228 };
30229
30230 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30231     
30232     fieldLabel : '',
30233     labelAlign : 'top',
30234     labelWidth : 3,
30235     dayAllowBlank : false,
30236     monthAllowBlank : false,
30237     yearAllowBlank : false,
30238     dayPlaceholder : '',
30239     monthPlaceholder : '',
30240     yearPlaceholder : '',
30241     dayFormat : 'd',
30242     monthFormat : 'm',
30243     yearFormat : 'Y',
30244     isFormField : true,
30245     labellg : 0,
30246     labelmd : 0,
30247     labelsm : 0,
30248     labelxs : 0,
30249     
30250     getAutoCreate : function()
30251     {
30252         var cfg = {
30253             tag : 'div',
30254             cls : 'row roo-date-split-field-group',
30255             cn : [
30256                 {
30257                     tag : 'input',
30258                     type : 'hidden',
30259                     cls : 'form-hidden-field roo-date-split-field-group-value',
30260                     name : this.name
30261                 }
30262             ]
30263         };
30264         
30265         var labelCls = 'col-md-12';
30266         var contentCls = 'col-md-4';
30267         
30268         if(this.fieldLabel){
30269             
30270             var label = {
30271                 tag : 'div',
30272                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30273                 cn : [
30274                     {
30275                         tag : 'label',
30276                         html : this.fieldLabel
30277                     }
30278                 ]
30279             };
30280             
30281             if(this.labelAlign == 'left'){
30282             
30283                 if(this.labelWidth > 12){
30284                     label.style = "width: " + this.labelWidth + 'px';
30285                 }
30286
30287                 if(this.labelWidth < 13 && this.labelmd == 0){
30288                     this.labelmd = this.labelWidth;
30289                 }
30290
30291                 if(this.labellg > 0){
30292                     labelCls = ' col-lg-' + this.labellg;
30293                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30294                 }
30295
30296                 if(this.labelmd > 0){
30297                     labelCls = ' col-md-' + this.labelmd;
30298                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30299                 }
30300
30301                 if(this.labelsm > 0){
30302                     labelCls = ' col-sm-' + this.labelsm;
30303                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30304                 }
30305
30306                 if(this.labelxs > 0){
30307                     labelCls = ' col-xs-' + this.labelxs;
30308                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30309                 }
30310             }
30311             
30312             label.cls += ' ' + labelCls;
30313             
30314             cfg.cn.push(label);
30315         }
30316         
30317         Roo.each(['day', 'month', 'year'], function(t){
30318             cfg.cn.push({
30319                 tag : 'div',
30320                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30321             });
30322         }, this);
30323         
30324         return cfg;
30325     },
30326     
30327     inputEl: function ()
30328     {
30329         return this.el.select('.roo-date-split-field-group-value', true).first();
30330     },
30331     
30332     onRender : function(ct, position) 
30333     {
30334         var _this = this;
30335         
30336         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30337         
30338         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30339         
30340         this.dayField = new Roo.bootstrap.ComboBox({
30341             allowBlank : this.dayAllowBlank,
30342             alwaysQuery : true,
30343             displayField : 'value',
30344             editable : false,
30345             fieldLabel : '',
30346             forceSelection : true,
30347             mode : 'local',
30348             placeholder : this.dayPlaceholder,
30349             selectOnFocus : true,
30350             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30351             triggerAction : 'all',
30352             typeAhead : true,
30353             valueField : 'value',
30354             store : new Roo.data.SimpleStore({
30355                 data : (function() {    
30356                     var days = [];
30357                     _this.fireEvent('days', _this, days);
30358                     return days;
30359                 })(),
30360                 fields : [ 'value' ]
30361             }),
30362             listeners : {
30363                 select : function (_self, record, index)
30364                 {
30365                     _this.setValue(_this.getValue());
30366                 }
30367             }
30368         });
30369
30370         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30371         
30372         this.monthField = new Roo.bootstrap.MonthField({
30373             after : '<i class=\"fa fa-calendar\"></i>',
30374             allowBlank : this.monthAllowBlank,
30375             placeholder : this.monthPlaceholder,
30376             readOnly : true,
30377             listeners : {
30378                 render : function (_self)
30379                 {
30380                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30381                         e.preventDefault();
30382                         _self.focus();
30383                     });
30384                 },
30385                 select : function (_self, oldvalue, newvalue)
30386                 {
30387                     _this.setValue(_this.getValue());
30388                 }
30389             }
30390         });
30391         
30392         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30393         
30394         this.yearField = new Roo.bootstrap.ComboBox({
30395             allowBlank : this.yearAllowBlank,
30396             alwaysQuery : true,
30397             displayField : 'value',
30398             editable : false,
30399             fieldLabel : '',
30400             forceSelection : true,
30401             mode : 'local',
30402             placeholder : this.yearPlaceholder,
30403             selectOnFocus : true,
30404             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30405             triggerAction : 'all',
30406             typeAhead : true,
30407             valueField : 'value',
30408             store : new Roo.data.SimpleStore({
30409                 data : (function() {
30410                     var years = [];
30411                     _this.fireEvent('years', _this, years);
30412                     return years;
30413                 })(),
30414                 fields : [ 'value' ]
30415             }),
30416             listeners : {
30417                 select : function (_self, record, index)
30418                 {
30419                     _this.setValue(_this.getValue());
30420                 }
30421             }
30422         });
30423
30424         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30425     },
30426     
30427     setValue : function(v, format)
30428     {
30429         this.inputEl.dom.value = v;
30430         
30431         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30432         
30433         var d = Date.parseDate(v, f);
30434         
30435         if(!d){
30436             this.validate();
30437             return;
30438         }
30439         
30440         this.setDay(d.format(this.dayFormat));
30441         this.setMonth(d.format(this.monthFormat));
30442         this.setYear(d.format(this.yearFormat));
30443         
30444         this.validate();
30445         
30446         return;
30447     },
30448     
30449     setDay : function(v)
30450     {
30451         this.dayField.setValue(v);
30452         this.inputEl.dom.value = this.getValue();
30453         this.validate();
30454         return;
30455     },
30456     
30457     setMonth : function(v)
30458     {
30459         this.monthField.setValue(v, true);
30460         this.inputEl.dom.value = this.getValue();
30461         this.validate();
30462         return;
30463     },
30464     
30465     setYear : function(v)
30466     {
30467         this.yearField.setValue(v);
30468         this.inputEl.dom.value = this.getValue();
30469         this.validate();
30470         return;
30471     },
30472     
30473     getDay : function()
30474     {
30475         return this.dayField.getValue();
30476     },
30477     
30478     getMonth : function()
30479     {
30480         return this.monthField.getValue();
30481     },
30482     
30483     getYear : function()
30484     {
30485         return this.yearField.getValue();
30486     },
30487     
30488     getValue : function()
30489     {
30490         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30491         
30492         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30493         
30494         return date;
30495     },
30496     
30497     reset : function()
30498     {
30499         this.setDay('');
30500         this.setMonth('');
30501         this.setYear('');
30502         this.inputEl.dom.value = '';
30503         this.validate();
30504         return;
30505     },
30506     
30507     validate : function()
30508     {
30509         var d = this.dayField.validate();
30510         var m = this.monthField.validate();
30511         var y = this.yearField.validate();
30512         
30513         var valid = true;
30514         
30515         if(
30516                 (!this.dayAllowBlank && !d) ||
30517                 (!this.monthAllowBlank && !m) ||
30518                 (!this.yearAllowBlank && !y)
30519         ){
30520             valid = false;
30521         }
30522         
30523         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30524             return valid;
30525         }
30526         
30527         if(valid){
30528             this.markValid();
30529             return valid;
30530         }
30531         
30532         this.markInvalid();
30533         
30534         return valid;
30535     },
30536     
30537     markValid : function()
30538     {
30539         
30540         var label = this.el.select('label', true).first();
30541         var icon = this.el.select('i.fa-star', true).first();
30542
30543         if(label && icon){
30544             icon.remove();
30545         }
30546         
30547         this.fireEvent('valid', this);
30548     },
30549     
30550      /**
30551      * Mark this field as invalid
30552      * @param {String} msg The validation message
30553      */
30554     markInvalid : function(msg)
30555     {
30556         
30557         var label = this.el.select('label', true).first();
30558         var icon = this.el.select('i.fa-star', true).first();
30559
30560         if(label && !icon){
30561             this.el.select('.roo-date-split-field-label', true).createChild({
30562                 tag : 'i',
30563                 cls : 'text-danger fa fa-lg fa-star',
30564                 tooltip : 'This field is required',
30565                 style : 'margin-right:5px;'
30566             }, label, true);
30567         }
30568         
30569         this.fireEvent('invalid', this, msg);
30570     },
30571     
30572     clearInvalid : function()
30573     {
30574         var label = this.el.select('label', true).first();
30575         var icon = this.el.select('i.fa-star', true).first();
30576
30577         if(label && icon){
30578             icon.remove();
30579         }
30580         
30581         this.fireEvent('valid', this);
30582     },
30583     
30584     getName: function()
30585     {
30586         return this.name;
30587     }
30588     
30589 });
30590
30591  /**
30592  *
30593  * This is based on 
30594  * http://masonry.desandro.com
30595  *
30596  * The idea is to render all the bricks based on vertical width...
30597  *
30598  * The original code extends 'outlayer' - we might need to use that....
30599  * 
30600  */
30601
30602
30603 /**
30604  * @class Roo.bootstrap.LayoutMasonry
30605  * @extends Roo.bootstrap.Component
30606  * Bootstrap Layout Masonry class
30607  * 
30608  * @constructor
30609  * Create a new Element
30610  * @param {Object} config The config object
30611  */
30612
30613 Roo.bootstrap.LayoutMasonry = function(config){
30614     
30615     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30616     
30617     this.bricks = [];
30618     
30619     Roo.bootstrap.LayoutMasonry.register(this);
30620     
30621     this.addEvents({
30622         // raw events
30623         /**
30624          * @event layout
30625          * Fire after layout the items
30626          * @param {Roo.bootstrap.LayoutMasonry} this
30627          * @param {Roo.EventObject} e
30628          */
30629         "layout" : true
30630     });
30631     
30632 };
30633
30634 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30635     
30636     /**
30637      * @cfg {Boolean} isLayoutInstant = no animation?
30638      */   
30639     isLayoutInstant : false, // needed?
30640    
30641     /**
30642      * @cfg {Number} boxWidth  width of the columns
30643      */   
30644     boxWidth : 450,
30645     
30646       /**
30647      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30648      */   
30649     boxHeight : 0,
30650     
30651     /**
30652      * @cfg {Number} padWidth padding below box..
30653      */   
30654     padWidth : 10, 
30655     
30656     /**
30657      * @cfg {Number} gutter gutter width..
30658      */   
30659     gutter : 10,
30660     
30661      /**
30662      * @cfg {Number} maxCols maximum number of columns
30663      */   
30664     
30665     maxCols: 0,
30666     
30667     /**
30668      * @cfg {Boolean} isAutoInitial defalut true
30669      */   
30670     isAutoInitial : true, 
30671     
30672     containerWidth: 0,
30673     
30674     /**
30675      * @cfg {Boolean} isHorizontal defalut false
30676      */   
30677     isHorizontal : false, 
30678
30679     currentSize : null,
30680     
30681     tag: 'div',
30682     
30683     cls: '',
30684     
30685     bricks: null, //CompositeElement
30686     
30687     cols : 1,
30688     
30689     _isLayoutInited : false,
30690     
30691 //    isAlternative : false, // only use for vertical layout...
30692     
30693     /**
30694      * @cfg {Number} alternativePadWidth padding below box..
30695      */   
30696     alternativePadWidth : 50,
30697     
30698     selectedBrick : [],
30699     
30700     getAutoCreate : function(){
30701         
30702         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30703         
30704         var cfg = {
30705             tag: this.tag,
30706             cls: 'blog-masonary-wrapper ' + this.cls,
30707             cn : {
30708                 cls : 'mas-boxes masonary'
30709             }
30710         };
30711         
30712         return cfg;
30713     },
30714     
30715     getChildContainer: function( )
30716     {
30717         if (this.boxesEl) {
30718             return this.boxesEl;
30719         }
30720         
30721         this.boxesEl = this.el.select('.mas-boxes').first();
30722         
30723         return this.boxesEl;
30724     },
30725     
30726     
30727     initEvents : function()
30728     {
30729         var _this = this;
30730         
30731         if(this.isAutoInitial){
30732             Roo.log('hook children rendered');
30733             this.on('childrenrendered', function() {
30734                 Roo.log('children rendered');
30735                 _this.initial();
30736             } ,this);
30737         }
30738     },
30739     
30740     initial : function()
30741     {
30742         this.selectedBrick = [];
30743         
30744         this.currentSize = this.el.getBox(true);
30745         
30746         Roo.EventManager.onWindowResize(this.resize, this); 
30747
30748         if(!this.isAutoInitial){
30749             this.layout();
30750             return;
30751         }
30752         
30753         this.layout();
30754         
30755         return;
30756         //this.layout.defer(500,this);
30757         
30758     },
30759     
30760     resize : function()
30761     {
30762         var cs = this.el.getBox(true);
30763         
30764         if (
30765                 this.currentSize.width == cs.width && 
30766                 this.currentSize.x == cs.x && 
30767                 this.currentSize.height == cs.height && 
30768                 this.currentSize.y == cs.y 
30769         ) {
30770             Roo.log("no change in with or X or Y");
30771             return;
30772         }
30773         
30774         this.currentSize = cs;
30775         
30776         this.layout();
30777         
30778     },
30779     
30780     layout : function()
30781     {   
30782         this._resetLayout();
30783         
30784         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30785         
30786         this.layoutItems( isInstant );
30787       
30788         this._isLayoutInited = true;
30789         
30790         this.fireEvent('layout', this);
30791         
30792     },
30793     
30794     _resetLayout : function()
30795     {
30796         if(this.isHorizontal){
30797             this.horizontalMeasureColumns();
30798             return;
30799         }
30800         
30801         this.verticalMeasureColumns();
30802         
30803     },
30804     
30805     verticalMeasureColumns : function()
30806     {
30807         this.getContainerWidth();
30808         
30809 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30810 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30811 //            return;
30812 //        }
30813         
30814         var boxWidth = this.boxWidth + this.padWidth;
30815         
30816         if(this.containerWidth < this.boxWidth){
30817             boxWidth = this.containerWidth
30818         }
30819         
30820         var containerWidth = this.containerWidth;
30821         
30822         var cols = Math.floor(containerWidth / boxWidth);
30823         
30824         this.cols = Math.max( cols, 1 );
30825         
30826         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30827         
30828         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30829         
30830         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30831         
30832         this.colWidth = boxWidth + avail - this.padWidth;
30833         
30834         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30835         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30836     },
30837     
30838     horizontalMeasureColumns : function()
30839     {
30840         this.getContainerWidth();
30841         
30842         var boxWidth = this.boxWidth;
30843         
30844         if(this.containerWidth < boxWidth){
30845             boxWidth = this.containerWidth;
30846         }
30847         
30848         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30849         
30850         this.el.setHeight(boxWidth);
30851         
30852     },
30853     
30854     getContainerWidth : function()
30855     {
30856         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30857     },
30858     
30859     layoutItems : function( isInstant )
30860     {
30861         Roo.log(this.bricks);
30862         
30863         var items = Roo.apply([], this.bricks);
30864         
30865         if(this.isHorizontal){
30866             this._horizontalLayoutItems( items , isInstant );
30867             return;
30868         }
30869         
30870 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30871 //            this._verticalAlternativeLayoutItems( items , isInstant );
30872 //            return;
30873 //        }
30874         
30875         this._verticalLayoutItems( items , isInstant );
30876         
30877     },
30878     
30879     _verticalLayoutItems : function ( items , isInstant)
30880     {
30881         if ( !items || !items.length ) {
30882             return;
30883         }
30884         
30885         var standard = [
30886             ['xs', 'xs', 'xs', 'tall'],
30887             ['xs', 'xs', 'tall'],
30888             ['xs', 'xs', 'sm'],
30889             ['xs', 'xs', 'xs'],
30890             ['xs', 'tall'],
30891             ['xs', 'sm'],
30892             ['xs', 'xs'],
30893             ['xs'],
30894             
30895             ['sm', 'xs', 'xs'],
30896             ['sm', 'xs'],
30897             ['sm'],
30898             
30899             ['tall', 'xs', 'xs', 'xs'],
30900             ['tall', 'xs', 'xs'],
30901             ['tall', 'xs'],
30902             ['tall']
30903             
30904         ];
30905         
30906         var queue = [];
30907         
30908         var boxes = [];
30909         
30910         var box = [];
30911         
30912         Roo.each(items, function(item, k){
30913             
30914             switch (item.size) {
30915                 // these layouts take up a full box,
30916                 case 'md' :
30917                 case 'md-left' :
30918                 case 'md-right' :
30919                 case 'wide' :
30920                     
30921                     if(box.length){
30922                         boxes.push(box);
30923                         box = [];
30924                     }
30925                     
30926                     boxes.push([item]);
30927                     
30928                     break;
30929                     
30930                 case 'xs' :
30931                 case 'sm' :
30932                 case 'tall' :
30933                     
30934                     box.push(item);
30935                     
30936                     break;
30937                 default :
30938                     break;
30939                     
30940             }
30941             
30942         }, this);
30943         
30944         if(box.length){
30945             boxes.push(box);
30946             box = [];
30947         }
30948         
30949         var filterPattern = function(box, length)
30950         {
30951             if(!box.length){
30952                 return;
30953             }
30954             
30955             var match = false;
30956             
30957             var pattern = box.slice(0, length);
30958             
30959             var format = [];
30960             
30961             Roo.each(pattern, function(i){
30962                 format.push(i.size);
30963             }, this);
30964             
30965             Roo.each(standard, function(s){
30966                 
30967                 if(String(s) != String(format)){
30968                     return;
30969                 }
30970                 
30971                 match = true;
30972                 return false;
30973                 
30974             }, this);
30975             
30976             if(!match && length == 1){
30977                 return;
30978             }
30979             
30980             if(!match){
30981                 filterPattern(box, length - 1);
30982                 return;
30983             }
30984                 
30985             queue.push(pattern);
30986
30987             box = box.slice(length, box.length);
30988
30989             filterPattern(box, 4);
30990
30991             return;
30992             
30993         }
30994         
30995         Roo.each(boxes, function(box, k){
30996             
30997             if(!box.length){
30998                 return;
30999             }
31000             
31001             if(box.length == 1){
31002                 queue.push(box);
31003                 return;
31004             }
31005             
31006             filterPattern(box, 4);
31007             
31008         }, this);
31009         
31010         this._processVerticalLayoutQueue( queue, isInstant );
31011         
31012     },
31013     
31014 //    _verticalAlternativeLayoutItems : function( items , isInstant )
31015 //    {
31016 //        if ( !items || !items.length ) {
31017 //            return;
31018 //        }
31019 //
31020 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
31021 //        
31022 //    },
31023     
31024     _horizontalLayoutItems : function ( items , isInstant)
31025     {
31026         if ( !items || !items.length || items.length < 3) {
31027             return;
31028         }
31029         
31030         items.reverse();
31031         
31032         var eItems = items.slice(0, 3);
31033         
31034         items = items.slice(3, items.length);
31035         
31036         var standard = [
31037             ['xs', 'xs', 'xs', 'wide'],
31038             ['xs', 'xs', 'wide'],
31039             ['xs', 'xs', 'sm'],
31040             ['xs', 'xs', 'xs'],
31041             ['xs', 'wide'],
31042             ['xs', 'sm'],
31043             ['xs', 'xs'],
31044             ['xs'],
31045             
31046             ['sm', 'xs', 'xs'],
31047             ['sm', 'xs'],
31048             ['sm'],
31049             
31050             ['wide', 'xs', 'xs', 'xs'],
31051             ['wide', 'xs', 'xs'],
31052             ['wide', 'xs'],
31053             ['wide'],
31054             
31055             ['wide-thin']
31056         ];
31057         
31058         var queue = [];
31059         
31060         var boxes = [];
31061         
31062         var box = [];
31063         
31064         Roo.each(items, function(item, k){
31065             
31066             switch (item.size) {
31067                 case 'md' :
31068                 case 'md-left' :
31069                 case 'md-right' :
31070                 case 'tall' :
31071                     
31072                     if(box.length){
31073                         boxes.push(box);
31074                         box = [];
31075                     }
31076                     
31077                     boxes.push([item]);
31078                     
31079                     break;
31080                     
31081                 case 'xs' :
31082                 case 'sm' :
31083                 case 'wide' :
31084                 case 'wide-thin' :
31085                     
31086                     box.push(item);
31087                     
31088                     break;
31089                 default :
31090                     break;
31091                     
31092             }
31093             
31094         }, this);
31095         
31096         if(box.length){
31097             boxes.push(box);
31098             box = [];
31099         }
31100         
31101         var filterPattern = function(box, length)
31102         {
31103             if(!box.length){
31104                 return;
31105             }
31106             
31107             var match = false;
31108             
31109             var pattern = box.slice(0, length);
31110             
31111             var format = [];
31112             
31113             Roo.each(pattern, function(i){
31114                 format.push(i.size);
31115             }, this);
31116             
31117             Roo.each(standard, function(s){
31118                 
31119                 if(String(s) != String(format)){
31120                     return;
31121                 }
31122                 
31123                 match = true;
31124                 return false;
31125                 
31126             }, this);
31127             
31128             if(!match && length == 1){
31129                 return;
31130             }
31131             
31132             if(!match){
31133                 filterPattern(box, length - 1);
31134                 return;
31135             }
31136                 
31137             queue.push(pattern);
31138
31139             box = box.slice(length, box.length);
31140
31141             filterPattern(box, 4);
31142
31143             return;
31144             
31145         }
31146         
31147         Roo.each(boxes, function(box, k){
31148             
31149             if(!box.length){
31150                 return;
31151             }
31152             
31153             if(box.length == 1){
31154                 queue.push(box);
31155                 return;
31156             }
31157             
31158             filterPattern(box, 4);
31159             
31160         }, this);
31161         
31162         
31163         var prune = [];
31164         
31165         var pos = this.el.getBox(true);
31166         
31167         var minX = pos.x;
31168         
31169         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31170         
31171         var hit_end = false;
31172         
31173         Roo.each(queue, function(box){
31174             
31175             if(hit_end){
31176                 
31177                 Roo.each(box, function(b){
31178                 
31179                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31180                     b.el.hide();
31181
31182                 }, this);
31183
31184                 return;
31185             }
31186             
31187             var mx = 0;
31188             
31189             Roo.each(box, function(b){
31190                 
31191                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31192                 b.el.show();
31193
31194                 mx = Math.max(mx, b.x);
31195                 
31196             }, this);
31197             
31198             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31199             
31200             if(maxX < minX){
31201                 
31202                 Roo.each(box, function(b){
31203                 
31204                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31205                     b.el.hide();
31206                     
31207                 }, this);
31208                 
31209                 hit_end = true;
31210                 
31211                 return;
31212             }
31213             
31214             prune.push(box);
31215             
31216         }, this);
31217         
31218         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31219     },
31220     
31221     /** Sets position of item in DOM
31222     * @param {Element} item
31223     * @param {Number} x - horizontal position
31224     * @param {Number} y - vertical position
31225     * @param {Boolean} isInstant - disables transitions
31226     */
31227     _processVerticalLayoutQueue : function( queue, isInstant )
31228     {
31229         var pos = this.el.getBox(true);
31230         var x = pos.x;
31231         var y = pos.y;
31232         var maxY = [];
31233         
31234         for (var i = 0; i < this.cols; i++){
31235             maxY[i] = pos.y;
31236         }
31237         
31238         Roo.each(queue, function(box, k){
31239             
31240             var col = k % this.cols;
31241             
31242             Roo.each(box, function(b,kk){
31243                 
31244                 b.el.position('absolute');
31245                 
31246                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31247                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31248                 
31249                 if(b.size == 'md-left' || b.size == 'md-right'){
31250                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31251                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31252                 }
31253                 
31254                 b.el.setWidth(width);
31255                 b.el.setHeight(height);
31256                 // iframe?
31257                 b.el.select('iframe',true).setSize(width,height);
31258                 
31259             }, this);
31260             
31261             for (var i = 0; i < this.cols; i++){
31262                 
31263                 if(maxY[i] < maxY[col]){
31264                     col = i;
31265                     continue;
31266                 }
31267                 
31268                 col = Math.min(col, i);
31269                 
31270             }
31271             
31272             x = pos.x + col * (this.colWidth + this.padWidth);
31273             
31274             y = maxY[col];
31275             
31276             var positions = [];
31277             
31278             switch (box.length){
31279                 case 1 :
31280                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31281                     break;
31282                 case 2 :
31283                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31284                     break;
31285                 case 3 :
31286                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31287                     break;
31288                 case 4 :
31289                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31290                     break;
31291                 default :
31292                     break;
31293             }
31294             
31295             Roo.each(box, function(b,kk){
31296                 
31297                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31298                 
31299                 var sz = b.el.getSize();
31300                 
31301                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31302                 
31303             }, this);
31304             
31305         }, this);
31306         
31307         var mY = 0;
31308         
31309         for (var i = 0; i < this.cols; i++){
31310             mY = Math.max(mY, maxY[i]);
31311         }
31312         
31313         this.el.setHeight(mY - pos.y);
31314         
31315     },
31316     
31317 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31318 //    {
31319 //        var pos = this.el.getBox(true);
31320 //        var x = pos.x;
31321 //        var y = pos.y;
31322 //        var maxX = pos.right;
31323 //        
31324 //        var maxHeight = 0;
31325 //        
31326 //        Roo.each(items, function(item, k){
31327 //            
31328 //            var c = k % 2;
31329 //            
31330 //            item.el.position('absolute');
31331 //                
31332 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31333 //
31334 //            item.el.setWidth(width);
31335 //
31336 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31337 //
31338 //            item.el.setHeight(height);
31339 //            
31340 //            if(c == 0){
31341 //                item.el.setXY([x, y], isInstant ? false : true);
31342 //            } else {
31343 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31344 //            }
31345 //            
31346 //            y = y + height + this.alternativePadWidth;
31347 //            
31348 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31349 //            
31350 //        }, this);
31351 //        
31352 //        this.el.setHeight(maxHeight);
31353 //        
31354 //    },
31355     
31356     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31357     {
31358         var pos = this.el.getBox(true);
31359         
31360         var minX = pos.x;
31361         var minY = pos.y;
31362         
31363         var maxX = pos.right;
31364         
31365         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31366         
31367         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31368         
31369         Roo.each(queue, function(box, k){
31370             
31371             Roo.each(box, function(b, kk){
31372                 
31373                 b.el.position('absolute');
31374                 
31375                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31376                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31377                 
31378                 if(b.size == 'md-left' || b.size == 'md-right'){
31379                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31380                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31381                 }
31382                 
31383                 b.el.setWidth(width);
31384                 b.el.setHeight(height);
31385                 
31386             }, this);
31387             
31388             if(!box.length){
31389                 return;
31390             }
31391             
31392             var positions = [];
31393             
31394             switch (box.length){
31395                 case 1 :
31396                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31397                     break;
31398                 case 2 :
31399                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31400                     break;
31401                 case 3 :
31402                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31403                     break;
31404                 case 4 :
31405                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31406                     break;
31407                 default :
31408                     break;
31409             }
31410             
31411             Roo.each(box, function(b,kk){
31412                 
31413                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31414                 
31415                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31416                 
31417             }, this);
31418             
31419         }, this);
31420         
31421     },
31422     
31423     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31424     {
31425         Roo.each(eItems, function(b,k){
31426             
31427             b.size = (k == 0) ? 'sm' : 'xs';
31428             b.x = (k == 0) ? 2 : 1;
31429             b.y = (k == 0) ? 2 : 1;
31430             
31431             b.el.position('absolute');
31432             
31433             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31434                 
31435             b.el.setWidth(width);
31436             
31437             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31438             
31439             b.el.setHeight(height);
31440             
31441         }, this);
31442
31443         var positions = [];
31444         
31445         positions.push({
31446             x : maxX - this.unitWidth * 2 - this.gutter,
31447             y : minY
31448         });
31449         
31450         positions.push({
31451             x : maxX - this.unitWidth,
31452             y : minY + (this.unitWidth + this.gutter) * 2
31453         });
31454         
31455         positions.push({
31456             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31457             y : minY
31458         });
31459         
31460         Roo.each(eItems, function(b,k){
31461             
31462             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31463
31464         }, this);
31465         
31466     },
31467     
31468     getVerticalOneBoxColPositions : function(x, y, box)
31469     {
31470         var pos = [];
31471         
31472         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31473         
31474         if(box[0].size == 'md-left'){
31475             rand = 0;
31476         }
31477         
31478         if(box[0].size == 'md-right'){
31479             rand = 1;
31480         }
31481         
31482         pos.push({
31483             x : x + (this.unitWidth + this.gutter) * rand,
31484             y : y
31485         });
31486         
31487         return pos;
31488     },
31489     
31490     getVerticalTwoBoxColPositions : function(x, y, box)
31491     {
31492         var pos = [];
31493         
31494         if(box[0].size == 'xs'){
31495             
31496             pos.push({
31497                 x : x,
31498                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31499             });
31500
31501             pos.push({
31502                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31503                 y : y
31504             });
31505             
31506             return pos;
31507             
31508         }
31509         
31510         pos.push({
31511             x : x,
31512             y : y
31513         });
31514
31515         pos.push({
31516             x : x + (this.unitWidth + this.gutter) * 2,
31517             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31518         });
31519         
31520         return pos;
31521         
31522     },
31523     
31524     getVerticalThreeBoxColPositions : function(x, y, box)
31525     {
31526         var pos = [];
31527         
31528         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31529             
31530             pos.push({
31531                 x : x,
31532                 y : y
31533             });
31534
31535             pos.push({
31536                 x : x + (this.unitWidth + this.gutter) * 1,
31537                 y : y
31538             });
31539             
31540             pos.push({
31541                 x : x + (this.unitWidth + this.gutter) * 2,
31542                 y : y
31543             });
31544             
31545             return pos;
31546             
31547         }
31548         
31549         if(box[0].size == 'xs' && box[1].size == 'xs'){
31550             
31551             pos.push({
31552                 x : x,
31553                 y : y
31554             });
31555
31556             pos.push({
31557                 x : x,
31558                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31559             });
31560             
31561             pos.push({
31562                 x : x + (this.unitWidth + this.gutter) * 1,
31563                 y : y
31564             });
31565             
31566             return pos;
31567             
31568         }
31569         
31570         pos.push({
31571             x : x,
31572             y : y
31573         });
31574
31575         pos.push({
31576             x : x + (this.unitWidth + this.gutter) * 2,
31577             y : y
31578         });
31579
31580         pos.push({
31581             x : x + (this.unitWidth + this.gutter) * 2,
31582             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31583         });
31584             
31585         return pos;
31586         
31587     },
31588     
31589     getVerticalFourBoxColPositions : function(x, y, box)
31590     {
31591         var pos = [];
31592         
31593         if(box[0].size == 'xs'){
31594             
31595             pos.push({
31596                 x : x,
31597                 y : y
31598             });
31599
31600             pos.push({
31601                 x : x,
31602                 y : y + (this.unitHeight + this.gutter) * 1
31603             });
31604             
31605             pos.push({
31606                 x : x,
31607                 y : y + (this.unitHeight + this.gutter) * 2
31608             });
31609             
31610             pos.push({
31611                 x : x + (this.unitWidth + this.gutter) * 1,
31612                 y : y
31613             });
31614             
31615             return pos;
31616             
31617         }
31618         
31619         pos.push({
31620             x : x,
31621             y : y
31622         });
31623
31624         pos.push({
31625             x : x + (this.unitWidth + this.gutter) * 2,
31626             y : y
31627         });
31628
31629         pos.push({
31630             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31631             y : y + (this.unitHeight + this.gutter) * 1
31632         });
31633
31634         pos.push({
31635             x : x + (this.unitWidth + this.gutter) * 2,
31636             y : y + (this.unitWidth + this.gutter) * 2
31637         });
31638
31639         return pos;
31640         
31641     },
31642     
31643     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31644     {
31645         var pos = [];
31646         
31647         if(box[0].size == 'md-left'){
31648             pos.push({
31649                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31650                 y : minY
31651             });
31652             
31653             return pos;
31654         }
31655         
31656         if(box[0].size == 'md-right'){
31657             pos.push({
31658                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31659                 y : minY + (this.unitWidth + this.gutter) * 1
31660             });
31661             
31662             return pos;
31663         }
31664         
31665         var rand = Math.floor(Math.random() * (4 - box[0].y));
31666         
31667         pos.push({
31668             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31669             y : minY + (this.unitWidth + this.gutter) * rand
31670         });
31671         
31672         return pos;
31673         
31674     },
31675     
31676     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31677     {
31678         var pos = [];
31679         
31680         if(box[0].size == 'xs'){
31681             
31682             pos.push({
31683                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31684                 y : minY
31685             });
31686
31687             pos.push({
31688                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31689                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31690             });
31691             
31692             return pos;
31693             
31694         }
31695         
31696         pos.push({
31697             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31698             y : minY
31699         });
31700
31701         pos.push({
31702             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31703             y : minY + (this.unitWidth + this.gutter) * 2
31704         });
31705         
31706         return pos;
31707         
31708     },
31709     
31710     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31711     {
31712         var pos = [];
31713         
31714         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31715             
31716             pos.push({
31717                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31718                 y : minY
31719             });
31720
31721             pos.push({
31722                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31723                 y : minY + (this.unitWidth + this.gutter) * 1
31724             });
31725             
31726             pos.push({
31727                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31728                 y : minY + (this.unitWidth + this.gutter) * 2
31729             });
31730             
31731             return pos;
31732             
31733         }
31734         
31735         if(box[0].size == 'xs' && box[1].size == 'xs'){
31736             
31737             pos.push({
31738                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31739                 y : minY
31740             });
31741
31742             pos.push({
31743                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31744                 y : minY
31745             });
31746             
31747             pos.push({
31748                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31749                 y : minY + (this.unitWidth + this.gutter) * 1
31750             });
31751             
31752             return pos;
31753             
31754         }
31755         
31756         pos.push({
31757             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31758             y : minY
31759         });
31760
31761         pos.push({
31762             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31763             y : minY + (this.unitWidth + this.gutter) * 2
31764         });
31765
31766         pos.push({
31767             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31768             y : minY + (this.unitWidth + this.gutter) * 2
31769         });
31770             
31771         return pos;
31772         
31773     },
31774     
31775     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31776     {
31777         var pos = [];
31778         
31779         if(box[0].size == 'xs'){
31780             
31781             pos.push({
31782                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31783                 y : minY
31784             });
31785
31786             pos.push({
31787                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31788                 y : minY
31789             });
31790             
31791             pos.push({
31792                 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),
31793                 y : minY
31794             });
31795             
31796             pos.push({
31797                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31798                 y : minY + (this.unitWidth + this.gutter) * 1
31799             });
31800             
31801             return pos;
31802             
31803         }
31804         
31805         pos.push({
31806             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31807             y : minY
31808         });
31809         
31810         pos.push({
31811             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31812             y : minY + (this.unitWidth + this.gutter) * 2
31813         });
31814         
31815         pos.push({
31816             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31817             y : minY + (this.unitWidth + this.gutter) * 2
31818         });
31819         
31820         pos.push({
31821             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),
31822             y : minY + (this.unitWidth + this.gutter) * 2
31823         });
31824
31825         return pos;
31826         
31827     },
31828     
31829     /**
31830     * remove a Masonry Brick
31831     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31832     */
31833     removeBrick : function(brick_id)
31834     {
31835         if (!brick_id) {
31836             return;
31837         }
31838         
31839         for (var i = 0; i<this.bricks.length; i++) {
31840             if (this.bricks[i].id == brick_id) {
31841                 this.bricks.splice(i,1);
31842                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31843                 this.initial();
31844             }
31845         }
31846     },
31847     
31848     /**
31849     * adds a Masonry Brick
31850     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31851     */
31852     addBrick : function(cfg)
31853     {
31854         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31855         //this.register(cn);
31856         cn.parentId = this.id;
31857         cn.onRender(this.el, null);
31858         return cn;
31859     },
31860     
31861     /**
31862     * register a Masonry Brick
31863     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31864     */
31865     
31866     register : function(brick)
31867     {
31868         this.bricks.push(brick);
31869         brick.masonryId = this.id;
31870     },
31871     
31872     /**
31873     * clear all the Masonry Brick
31874     */
31875     clearAll : function()
31876     {
31877         this.bricks = [];
31878         //this.getChildContainer().dom.innerHTML = "";
31879         this.el.dom.innerHTML = '';
31880     },
31881     
31882     getSelected : function()
31883     {
31884         if (!this.selectedBrick) {
31885             return false;
31886         }
31887         
31888         return this.selectedBrick;
31889     }
31890 });
31891
31892 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31893     
31894     groups: {},
31895      /**
31896     * register a Masonry Layout
31897     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31898     */
31899     
31900     register : function(layout)
31901     {
31902         this.groups[layout.id] = layout;
31903     },
31904     /**
31905     * fetch a  Masonry Layout based on the masonry layout ID
31906     * @param {string} the masonry layout to add
31907     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31908     */
31909     
31910     get: function(layout_id) {
31911         if (typeof(this.groups[layout_id]) == 'undefined') {
31912             return false;
31913         }
31914         return this.groups[layout_id] ;
31915     }
31916     
31917     
31918     
31919 });
31920
31921  
31922
31923  /**
31924  *
31925  * This is based on 
31926  * http://masonry.desandro.com
31927  *
31928  * The idea is to render all the bricks based on vertical width...
31929  *
31930  * The original code extends 'outlayer' - we might need to use that....
31931  * 
31932  */
31933
31934
31935 /**
31936  * @class Roo.bootstrap.LayoutMasonryAuto
31937  * @extends Roo.bootstrap.Component
31938  * Bootstrap Layout Masonry class
31939  * 
31940  * @constructor
31941  * Create a new Element
31942  * @param {Object} config The config object
31943  */
31944
31945 Roo.bootstrap.LayoutMasonryAuto = function(config){
31946     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31947 };
31948
31949 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31950     
31951       /**
31952      * @cfg {Boolean} isFitWidth  - resize the width..
31953      */   
31954     isFitWidth : false,  // options..
31955     /**
31956      * @cfg {Boolean} isOriginLeft = left align?
31957      */   
31958     isOriginLeft : true,
31959     /**
31960      * @cfg {Boolean} isOriginTop = top align?
31961      */   
31962     isOriginTop : false,
31963     /**
31964      * @cfg {Boolean} isLayoutInstant = no animation?
31965      */   
31966     isLayoutInstant : false, // needed?
31967     /**
31968      * @cfg {Boolean} isResizingContainer = not sure if this is used..
31969      */   
31970     isResizingContainer : true,
31971     /**
31972      * @cfg {Number} columnWidth  width of the columns 
31973      */   
31974     
31975     columnWidth : 0,
31976     
31977     /**
31978      * @cfg {Number} maxCols maximum number of columns
31979      */   
31980     
31981     maxCols: 0,
31982     /**
31983      * @cfg {Number} padHeight padding below box..
31984      */   
31985     
31986     padHeight : 10, 
31987     
31988     /**
31989      * @cfg {Boolean} isAutoInitial defalut true
31990      */   
31991     
31992     isAutoInitial : true, 
31993     
31994     // private?
31995     gutter : 0,
31996     
31997     containerWidth: 0,
31998     initialColumnWidth : 0,
31999     currentSize : null,
32000     
32001     colYs : null, // array.
32002     maxY : 0,
32003     padWidth: 10,
32004     
32005     
32006     tag: 'div',
32007     cls: '',
32008     bricks: null, //CompositeElement
32009     cols : 0, // array?
32010     // element : null, // wrapped now this.el
32011     _isLayoutInited : null, 
32012     
32013     
32014     getAutoCreate : function(){
32015         
32016         var cfg = {
32017             tag: this.tag,
32018             cls: 'blog-masonary-wrapper ' + this.cls,
32019             cn : {
32020                 cls : 'mas-boxes masonary'
32021             }
32022         };
32023         
32024         return cfg;
32025     },
32026     
32027     getChildContainer: function( )
32028     {
32029         if (this.boxesEl) {
32030             return this.boxesEl;
32031         }
32032         
32033         this.boxesEl = this.el.select('.mas-boxes').first();
32034         
32035         return this.boxesEl;
32036     },
32037     
32038     
32039     initEvents : function()
32040     {
32041         var _this = this;
32042         
32043         if(this.isAutoInitial){
32044             Roo.log('hook children rendered');
32045             this.on('childrenrendered', function() {
32046                 Roo.log('children rendered');
32047                 _this.initial();
32048             } ,this);
32049         }
32050         
32051     },
32052     
32053     initial : function()
32054     {
32055         this.reloadItems();
32056
32057         this.currentSize = this.el.getBox(true);
32058
32059         /// was window resize... - let's see if this works..
32060         Roo.EventManager.onWindowResize(this.resize, this); 
32061
32062         if(!this.isAutoInitial){
32063             this.layout();
32064             return;
32065         }
32066         
32067         this.layout.defer(500,this);
32068     },
32069     
32070     reloadItems: function()
32071     {
32072         this.bricks = this.el.select('.masonry-brick', true);
32073         
32074         this.bricks.each(function(b) {
32075             //Roo.log(b.getSize());
32076             if (!b.attr('originalwidth')) {
32077                 b.attr('originalwidth',  b.getSize().width);
32078             }
32079             
32080         });
32081         
32082         Roo.log(this.bricks.elements.length);
32083     },
32084     
32085     resize : function()
32086     {
32087         Roo.log('resize');
32088         var cs = this.el.getBox(true);
32089         
32090         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32091             Roo.log("no change in with or X");
32092             return;
32093         }
32094         this.currentSize = cs;
32095         this.layout();
32096     },
32097     
32098     layout : function()
32099     {
32100          Roo.log('layout');
32101         this._resetLayout();
32102         //this._manageStamps();
32103       
32104         // don't animate first layout
32105         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32106         this.layoutItems( isInstant );
32107       
32108         // flag for initalized
32109         this._isLayoutInited = true;
32110     },
32111     
32112     layoutItems : function( isInstant )
32113     {
32114         //var items = this._getItemsForLayout( this.items );
32115         // original code supports filtering layout items.. we just ignore it..
32116         
32117         this._layoutItems( this.bricks , isInstant );
32118       
32119         this._postLayout();
32120     },
32121     _layoutItems : function ( items , isInstant)
32122     {
32123        //this.fireEvent( 'layout', this, items );
32124     
32125
32126         if ( !items || !items.elements.length ) {
32127           // no items, emit event with empty array
32128             return;
32129         }
32130
32131         var queue = [];
32132         items.each(function(item) {
32133             Roo.log("layout item");
32134             Roo.log(item);
32135             // get x/y object from method
32136             var position = this._getItemLayoutPosition( item );
32137             // enqueue
32138             position.item = item;
32139             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32140             queue.push( position );
32141         }, this);
32142       
32143         this._processLayoutQueue( queue );
32144     },
32145     /** Sets position of item in DOM
32146     * @param {Element} item
32147     * @param {Number} x - horizontal position
32148     * @param {Number} y - vertical position
32149     * @param {Boolean} isInstant - disables transitions
32150     */
32151     _processLayoutQueue : function( queue )
32152     {
32153         for ( var i=0, len = queue.length; i < len; i++ ) {
32154             var obj = queue[i];
32155             obj.item.position('absolute');
32156             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32157         }
32158     },
32159       
32160     
32161     /**
32162     * Any logic you want to do after each layout,
32163     * i.e. size the container
32164     */
32165     _postLayout : function()
32166     {
32167         this.resizeContainer();
32168     },
32169     
32170     resizeContainer : function()
32171     {
32172         if ( !this.isResizingContainer ) {
32173             return;
32174         }
32175         var size = this._getContainerSize();
32176         if ( size ) {
32177             this.el.setSize(size.width,size.height);
32178             this.boxesEl.setSize(size.width,size.height);
32179         }
32180     },
32181     
32182     
32183     
32184     _resetLayout : function()
32185     {
32186         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32187         this.colWidth = this.el.getWidth();
32188         //this.gutter = this.el.getWidth(); 
32189         
32190         this.measureColumns();
32191
32192         // reset column Y
32193         var i = this.cols;
32194         this.colYs = [];
32195         while (i--) {
32196             this.colYs.push( 0 );
32197         }
32198     
32199         this.maxY = 0;
32200     },
32201
32202     measureColumns : function()
32203     {
32204         this.getContainerWidth();
32205       // if columnWidth is 0, default to outerWidth of first item
32206         if ( !this.columnWidth ) {
32207             var firstItem = this.bricks.first();
32208             Roo.log(firstItem);
32209             this.columnWidth  = this.containerWidth;
32210             if (firstItem && firstItem.attr('originalwidth') ) {
32211                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32212             }
32213             // columnWidth fall back to item of first element
32214             Roo.log("set column width?");
32215                         this.initialColumnWidth = this.columnWidth  ;
32216
32217             // if first elem has no width, default to size of container
32218             
32219         }
32220         
32221         
32222         if (this.initialColumnWidth) {
32223             this.columnWidth = this.initialColumnWidth;
32224         }
32225         
32226         
32227             
32228         // column width is fixed at the top - however if container width get's smaller we should
32229         // reduce it...
32230         
32231         // this bit calcs how man columns..
32232             
32233         var columnWidth = this.columnWidth += this.gutter;
32234       
32235         // calculate columns
32236         var containerWidth = this.containerWidth + this.gutter;
32237         
32238         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32239         // fix rounding errors, typically with gutters
32240         var excess = columnWidth - containerWidth % columnWidth;
32241         
32242         
32243         // if overshoot is less than a pixel, round up, otherwise floor it
32244         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32245         cols = Math[ mathMethod ]( cols );
32246         this.cols = Math.max( cols, 1 );
32247         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32248         
32249          // padding positioning..
32250         var totalColWidth = this.cols * this.columnWidth;
32251         var padavail = this.containerWidth - totalColWidth;
32252         // so for 2 columns - we need 3 'pads'
32253         
32254         var padNeeded = (1+this.cols) * this.padWidth;
32255         
32256         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32257         
32258         this.columnWidth += padExtra
32259         //this.padWidth = Math.floor(padavail /  ( this.cols));
32260         
32261         // adjust colum width so that padding is fixed??
32262         
32263         // we have 3 columns ... total = width * 3
32264         // we have X left over... that should be used by 
32265         
32266         //if (this.expandC) {
32267             
32268         //}
32269         
32270         
32271         
32272     },
32273     
32274     getContainerWidth : function()
32275     {
32276        /* // container is parent if fit width
32277         var container = this.isFitWidth ? this.element.parentNode : this.element;
32278         // check that this.size and size are there
32279         // IE8 triggers resize on body size change, so they might not be
32280         
32281         var size = getSize( container );  //FIXME
32282         this.containerWidth = size && size.innerWidth; //FIXME
32283         */
32284          
32285         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32286         
32287     },
32288     
32289     _getItemLayoutPosition : function( item )  // what is item?
32290     {
32291         // we resize the item to our columnWidth..
32292       
32293         item.setWidth(this.columnWidth);
32294         item.autoBoxAdjust  = false;
32295         
32296         var sz = item.getSize();
32297  
32298         // how many columns does this brick span
32299         var remainder = this.containerWidth % this.columnWidth;
32300         
32301         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32302         // round if off by 1 pixel, otherwise use ceil
32303         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32304         colSpan = Math.min( colSpan, this.cols );
32305         
32306         // normally this should be '1' as we dont' currently allow multi width columns..
32307         
32308         var colGroup = this._getColGroup( colSpan );
32309         // get the minimum Y value from the columns
32310         var minimumY = Math.min.apply( Math, colGroup );
32311         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32312         
32313         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32314          
32315         // position the brick
32316         var position = {
32317             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32318             y: this.currentSize.y + minimumY + this.padHeight
32319         };
32320         
32321         Roo.log(position);
32322         // apply setHeight to necessary columns
32323         var setHeight = minimumY + sz.height + this.padHeight;
32324         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32325         
32326         var setSpan = this.cols + 1 - colGroup.length;
32327         for ( var i = 0; i < setSpan; i++ ) {
32328           this.colYs[ shortColIndex + i ] = setHeight ;
32329         }
32330       
32331         return position;
32332     },
32333     
32334     /**
32335      * @param {Number} colSpan - number of columns the element spans
32336      * @returns {Array} colGroup
32337      */
32338     _getColGroup : function( colSpan )
32339     {
32340         if ( colSpan < 2 ) {
32341           // if brick spans only one column, use all the column Ys
32342           return this.colYs;
32343         }
32344       
32345         var colGroup = [];
32346         // how many different places could this brick fit horizontally
32347         var groupCount = this.cols + 1 - colSpan;
32348         // for each group potential horizontal position
32349         for ( var i = 0; i < groupCount; i++ ) {
32350           // make an array of colY values for that one group
32351           var groupColYs = this.colYs.slice( i, i + colSpan );
32352           // and get the max value of the array
32353           colGroup[i] = Math.max.apply( Math, groupColYs );
32354         }
32355         return colGroup;
32356     },
32357     /*
32358     _manageStamp : function( stamp )
32359     {
32360         var stampSize =  stamp.getSize();
32361         var offset = stamp.getBox();
32362         // get the columns that this stamp affects
32363         var firstX = this.isOriginLeft ? offset.x : offset.right;
32364         var lastX = firstX + stampSize.width;
32365         var firstCol = Math.floor( firstX / this.columnWidth );
32366         firstCol = Math.max( 0, firstCol );
32367         
32368         var lastCol = Math.floor( lastX / this.columnWidth );
32369         // lastCol should not go over if multiple of columnWidth #425
32370         lastCol -= lastX % this.columnWidth ? 0 : 1;
32371         lastCol = Math.min( this.cols - 1, lastCol );
32372         
32373         // set colYs to bottom of the stamp
32374         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32375             stampSize.height;
32376             
32377         for ( var i = firstCol; i <= lastCol; i++ ) {
32378           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32379         }
32380     },
32381     */
32382     
32383     _getContainerSize : function()
32384     {
32385         this.maxY = Math.max.apply( Math, this.colYs );
32386         var size = {
32387             height: this.maxY
32388         };
32389       
32390         if ( this.isFitWidth ) {
32391             size.width = this._getContainerFitWidth();
32392         }
32393       
32394         return size;
32395     },
32396     
32397     _getContainerFitWidth : function()
32398     {
32399         var unusedCols = 0;
32400         // count unused columns
32401         var i = this.cols;
32402         while ( --i ) {
32403           if ( this.colYs[i] !== 0 ) {
32404             break;
32405           }
32406           unusedCols++;
32407         }
32408         // fit container to columns that have been used
32409         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32410     },
32411     
32412     needsResizeLayout : function()
32413     {
32414         var previousWidth = this.containerWidth;
32415         this.getContainerWidth();
32416         return previousWidth !== this.containerWidth;
32417     }
32418  
32419 });
32420
32421  
32422
32423  /*
32424  * - LGPL
32425  *
32426  * element
32427  * 
32428  */
32429
32430 /**
32431  * @class Roo.bootstrap.MasonryBrick
32432  * @extends Roo.bootstrap.Component
32433  * Bootstrap MasonryBrick class
32434  * 
32435  * @constructor
32436  * Create a new MasonryBrick
32437  * @param {Object} config The config object
32438  */
32439
32440 Roo.bootstrap.MasonryBrick = function(config){
32441     
32442     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32443     
32444     Roo.bootstrap.MasonryBrick.register(this);
32445     
32446     this.addEvents({
32447         // raw events
32448         /**
32449          * @event click
32450          * When a MasonryBrick is clcik
32451          * @param {Roo.bootstrap.MasonryBrick} this
32452          * @param {Roo.EventObject} e
32453          */
32454         "click" : true
32455     });
32456 };
32457
32458 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32459     
32460     /**
32461      * @cfg {String} title
32462      */   
32463     title : '',
32464     /**
32465      * @cfg {String} html
32466      */   
32467     html : '',
32468     /**
32469      * @cfg {String} bgimage
32470      */   
32471     bgimage : '',
32472     /**
32473      * @cfg {String} videourl
32474      */   
32475     videourl : '',
32476     /**
32477      * @cfg {String} cls
32478      */   
32479     cls : '',
32480     /**
32481      * @cfg {String} href
32482      */   
32483     href : '',
32484     /**
32485      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32486      */   
32487     size : 'xs',
32488     
32489     /**
32490      * @cfg {String} placetitle (center|bottom)
32491      */   
32492     placetitle : '',
32493     
32494     /**
32495      * @cfg {Boolean} isFitContainer defalut true
32496      */   
32497     isFitContainer : true, 
32498     
32499     /**
32500      * @cfg {Boolean} preventDefault defalut false
32501      */   
32502     preventDefault : false, 
32503     
32504     /**
32505      * @cfg {Boolean} inverse defalut false
32506      */   
32507     maskInverse : false, 
32508     
32509     getAutoCreate : function()
32510     {
32511         if(!this.isFitContainer){
32512             return this.getSplitAutoCreate();
32513         }
32514         
32515         var cls = 'masonry-brick masonry-brick-full';
32516         
32517         if(this.href.length){
32518             cls += ' masonry-brick-link';
32519         }
32520         
32521         if(this.bgimage.length){
32522             cls += ' masonry-brick-image';
32523         }
32524         
32525         if(this.maskInverse){
32526             cls += ' mask-inverse';
32527         }
32528         
32529         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32530             cls += ' enable-mask';
32531         }
32532         
32533         if(this.size){
32534             cls += ' masonry-' + this.size + '-brick';
32535         }
32536         
32537         if(this.placetitle.length){
32538             
32539             switch (this.placetitle) {
32540                 case 'center' :
32541                     cls += ' masonry-center-title';
32542                     break;
32543                 case 'bottom' :
32544                     cls += ' masonry-bottom-title';
32545                     break;
32546                 default:
32547                     break;
32548             }
32549             
32550         } else {
32551             if(!this.html.length && !this.bgimage.length){
32552                 cls += ' masonry-center-title';
32553             }
32554
32555             if(!this.html.length && this.bgimage.length){
32556                 cls += ' masonry-bottom-title';
32557             }
32558         }
32559         
32560         if(this.cls){
32561             cls += ' ' + this.cls;
32562         }
32563         
32564         var cfg = {
32565             tag: (this.href.length) ? 'a' : 'div',
32566             cls: cls,
32567             cn: [
32568                 {
32569                     tag: 'div',
32570                     cls: 'masonry-brick-mask'
32571                 },
32572                 {
32573                     tag: 'div',
32574                     cls: 'masonry-brick-paragraph',
32575                     cn: []
32576                 }
32577             ]
32578         };
32579         
32580         if(this.href.length){
32581             cfg.href = this.href;
32582         }
32583         
32584         var cn = cfg.cn[1].cn;
32585         
32586         if(this.title.length){
32587             cn.push({
32588                 tag: 'h4',
32589                 cls: 'masonry-brick-title',
32590                 html: this.title
32591             });
32592         }
32593         
32594         if(this.html.length){
32595             cn.push({
32596                 tag: 'p',
32597                 cls: 'masonry-brick-text',
32598                 html: this.html
32599             });
32600         }
32601         
32602         if (!this.title.length && !this.html.length) {
32603             cfg.cn[1].cls += ' hide';
32604         }
32605         
32606         if(this.bgimage.length){
32607             cfg.cn.push({
32608                 tag: 'img',
32609                 cls: 'masonry-brick-image-view',
32610                 src: this.bgimage
32611             });
32612         }
32613         
32614         if(this.videourl.length){
32615             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32616             // youtube support only?
32617             cfg.cn.push({
32618                 tag: 'iframe',
32619                 cls: 'masonry-brick-image-view',
32620                 src: vurl,
32621                 frameborder : 0,
32622                 allowfullscreen : true
32623             });
32624         }
32625         
32626         return cfg;
32627         
32628     },
32629     
32630     getSplitAutoCreate : function()
32631     {
32632         var cls = 'masonry-brick masonry-brick-split';
32633         
32634         if(this.href.length){
32635             cls += ' masonry-brick-link';
32636         }
32637         
32638         if(this.bgimage.length){
32639             cls += ' masonry-brick-image';
32640         }
32641         
32642         if(this.size){
32643             cls += ' masonry-' + this.size + '-brick';
32644         }
32645         
32646         switch (this.placetitle) {
32647             case 'center' :
32648                 cls += ' masonry-center-title';
32649                 break;
32650             case 'bottom' :
32651                 cls += ' masonry-bottom-title';
32652                 break;
32653             default:
32654                 if(!this.bgimage.length){
32655                     cls += ' masonry-center-title';
32656                 }
32657
32658                 if(this.bgimage.length){
32659                     cls += ' masonry-bottom-title';
32660                 }
32661                 break;
32662         }
32663         
32664         if(this.cls){
32665             cls += ' ' + this.cls;
32666         }
32667         
32668         var cfg = {
32669             tag: (this.href.length) ? 'a' : 'div',
32670             cls: cls,
32671             cn: [
32672                 {
32673                     tag: 'div',
32674                     cls: 'masonry-brick-split-head',
32675                     cn: [
32676                         {
32677                             tag: 'div',
32678                             cls: 'masonry-brick-paragraph',
32679                             cn: []
32680                         }
32681                     ]
32682                 },
32683                 {
32684                     tag: 'div',
32685                     cls: 'masonry-brick-split-body',
32686                     cn: []
32687                 }
32688             ]
32689         };
32690         
32691         if(this.href.length){
32692             cfg.href = this.href;
32693         }
32694         
32695         if(this.title.length){
32696             cfg.cn[0].cn[0].cn.push({
32697                 tag: 'h4',
32698                 cls: 'masonry-brick-title',
32699                 html: this.title
32700             });
32701         }
32702         
32703         if(this.html.length){
32704             cfg.cn[1].cn.push({
32705                 tag: 'p',
32706                 cls: 'masonry-brick-text',
32707                 html: this.html
32708             });
32709         }
32710
32711         if(this.bgimage.length){
32712             cfg.cn[0].cn.push({
32713                 tag: 'img',
32714                 cls: 'masonry-brick-image-view',
32715                 src: this.bgimage
32716             });
32717         }
32718         
32719         if(this.videourl.length){
32720             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32721             // youtube support only?
32722             cfg.cn[0].cn.cn.push({
32723                 tag: 'iframe',
32724                 cls: 'masonry-brick-image-view',
32725                 src: vurl,
32726                 frameborder : 0,
32727                 allowfullscreen : true
32728             });
32729         }
32730         
32731         return cfg;
32732     },
32733     
32734     initEvents: function() 
32735     {
32736         switch (this.size) {
32737             case 'xs' :
32738                 this.x = 1;
32739                 this.y = 1;
32740                 break;
32741             case 'sm' :
32742                 this.x = 2;
32743                 this.y = 2;
32744                 break;
32745             case 'md' :
32746             case 'md-left' :
32747             case 'md-right' :
32748                 this.x = 3;
32749                 this.y = 3;
32750                 break;
32751             case 'tall' :
32752                 this.x = 2;
32753                 this.y = 3;
32754                 break;
32755             case 'wide' :
32756                 this.x = 3;
32757                 this.y = 2;
32758                 break;
32759             case 'wide-thin' :
32760                 this.x = 3;
32761                 this.y = 1;
32762                 break;
32763                         
32764             default :
32765                 break;
32766         }
32767         
32768         if(Roo.isTouch){
32769             this.el.on('touchstart', this.onTouchStart, this);
32770             this.el.on('touchmove', this.onTouchMove, this);
32771             this.el.on('touchend', this.onTouchEnd, this);
32772             this.el.on('contextmenu', this.onContextMenu, this);
32773         } else {
32774             this.el.on('mouseenter'  ,this.enter, this);
32775             this.el.on('mouseleave', this.leave, this);
32776             this.el.on('click', this.onClick, this);
32777         }
32778         
32779         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32780             this.parent().bricks.push(this);   
32781         }
32782         
32783     },
32784     
32785     onClick: function(e, el)
32786     {
32787         var time = this.endTimer - this.startTimer;
32788         // Roo.log(e.preventDefault());
32789         if(Roo.isTouch){
32790             if(time > 1000){
32791                 e.preventDefault();
32792                 return;
32793             }
32794         }
32795         
32796         if(!this.preventDefault){
32797             return;
32798         }
32799         
32800         e.preventDefault();
32801         
32802         if (this.activeClass != '') {
32803             this.selectBrick();
32804         }
32805         
32806         this.fireEvent('click', this, e);
32807     },
32808     
32809     enter: function(e, el)
32810     {
32811         e.preventDefault();
32812         
32813         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32814             return;
32815         }
32816         
32817         if(this.bgimage.length && this.html.length){
32818             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32819         }
32820     },
32821     
32822     leave: function(e, el)
32823     {
32824         e.preventDefault();
32825         
32826         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32827             return;
32828         }
32829         
32830         if(this.bgimage.length && this.html.length){
32831             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32832         }
32833     },
32834     
32835     onTouchStart: function(e, el)
32836     {
32837 //        e.preventDefault();
32838         
32839         this.touchmoved = false;
32840         
32841         if(!this.isFitContainer){
32842             return;
32843         }
32844         
32845         if(!this.bgimage.length || !this.html.length){
32846             return;
32847         }
32848         
32849         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32850         
32851         this.timer = new Date().getTime();
32852         
32853     },
32854     
32855     onTouchMove: function(e, el)
32856     {
32857         this.touchmoved = true;
32858     },
32859     
32860     onContextMenu : function(e,el)
32861     {
32862         e.preventDefault();
32863         e.stopPropagation();
32864         return false;
32865     },
32866     
32867     onTouchEnd: function(e, el)
32868     {
32869 //        e.preventDefault();
32870         
32871         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32872         
32873             this.leave(e,el);
32874             
32875             return;
32876         }
32877         
32878         if(!this.bgimage.length || !this.html.length){
32879             
32880             if(this.href.length){
32881                 window.location.href = this.href;
32882             }
32883             
32884             return;
32885         }
32886         
32887         if(!this.isFitContainer){
32888             return;
32889         }
32890         
32891         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32892         
32893         window.location.href = this.href;
32894     },
32895     
32896     //selection on single brick only
32897     selectBrick : function() {
32898         
32899         if (!this.parentId) {
32900             return;
32901         }
32902         
32903         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32904         var index = m.selectedBrick.indexOf(this.id);
32905         
32906         if ( index > -1) {
32907             m.selectedBrick.splice(index,1);
32908             this.el.removeClass(this.activeClass);
32909             return;
32910         }
32911         
32912         for(var i = 0; i < m.selectedBrick.length; i++) {
32913             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32914             b.el.removeClass(b.activeClass);
32915         }
32916         
32917         m.selectedBrick = [];
32918         
32919         m.selectedBrick.push(this.id);
32920         this.el.addClass(this.activeClass);
32921         return;
32922     },
32923     
32924     isSelected : function(){
32925         return this.el.hasClass(this.activeClass);
32926         
32927     }
32928 });
32929
32930 Roo.apply(Roo.bootstrap.MasonryBrick, {
32931     
32932     //groups: {},
32933     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32934      /**
32935     * register a Masonry Brick
32936     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32937     */
32938     
32939     register : function(brick)
32940     {
32941         //this.groups[brick.id] = brick;
32942         this.groups.add(brick.id, brick);
32943     },
32944     /**
32945     * fetch a  masonry brick based on the masonry brick ID
32946     * @param {string} the masonry brick to add
32947     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32948     */
32949     
32950     get: function(brick_id) 
32951     {
32952         // if (typeof(this.groups[brick_id]) == 'undefined') {
32953         //     return false;
32954         // }
32955         // return this.groups[brick_id] ;
32956         
32957         if(this.groups.key(brick_id)) {
32958             return this.groups.key(brick_id);
32959         }
32960         
32961         return false;
32962     }
32963     
32964     
32965     
32966 });
32967
32968  /*
32969  * - LGPL
32970  *
32971  * element
32972  * 
32973  */
32974
32975 /**
32976  * @class Roo.bootstrap.Brick
32977  * @extends Roo.bootstrap.Component
32978  * Bootstrap Brick class
32979  * 
32980  * @constructor
32981  * Create a new Brick
32982  * @param {Object} config The config object
32983  */
32984
32985 Roo.bootstrap.Brick = function(config){
32986     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32987     
32988     this.addEvents({
32989         // raw events
32990         /**
32991          * @event click
32992          * When a Brick is click
32993          * @param {Roo.bootstrap.Brick} this
32994          * @param {Roo.EventObject} e
32995          */
32996         "click" : true
32997     });
32998 };
32999
33000 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
33001     
33002     /**
33003      * @cfg {String} title
33004      */   
33005     title : '',
33006     /**
33007      * @cfg {String} html
33008      */   
33009     html : '',
33010     /**
33011      * @cfg {String} bgimage
33012      */   
33013     bgimage : '',
33014     /**
33015      * @cfg {String} cls
33016      */   
33017     cls : '',
33018     /**
33019      * @cfg {String} href
33020      */   
33021     href : '',
33022     /**
33023      * @cfg {String} video
33024      */   
33025     video : '',
33026     /**
33027      * @cfg {Boolean} square
33028      */   
33029     square : true,
33030     
33031     getAutoCreate : function()
33032     {
33033         var cls = 'roo-brick';
33034         
33035         if(this.href.length){
33036             cls += ' roo-brick-link';
33037         }
33038         
33039         if(this.bgimage.length){
33040             cls += ' roo-brick-image';
33041         }
33042         
33043         if(!this.html.length && !this.bgimage.length){
33044             cls += ' roo-brick-center-title';
33045         }
33046         
33047         if(!this.html.length && this.bgimage.length){
33048             cls += ' roo-brick-bottom-title';
33049         }
33050         
33051         if(this.cls){
33052             cls += ' ' + this.cls;
33053         }
33054         
33055         var cfg = {
33056             tag: (this.href.length) ? 'a' : 'div',
33057             cls: cls,
33058             cn: [
33059                 {
33060                     tag: 'div',
33061                     cls: 'roo-brick-paragraph',
33062                     cn: []
33063                 }
33064             ]
33065         };
33066         
33067         if(this.href.length){
33068             cfg.href = this.href;
33069         }
33070         
33071         var cn = cfg.cn[0].cn;
33072         
33073         if(this.title.length){
33074             cn.push({
33075                 tag: 'h4',
33076                 cls: 'roo-brick-title',
33077                 html: this.title
33078             });
33079         }
33080         
33081         if(this.html.length){
33082             cn.push({
33083                 tag: 'p',
33084                 cls: 'roo-brick-text',
33085                 html: this.html
33086             });
33087         } else {
33088             cn.cls += ' hide';
33089         }
33090         
33091         if(this.bgimage.length){
33092             cfg.cn.push({
33093                 tag: 'img',
33094                 cls: 'roo-brick-image-view',
33095                 src: this.bgimage
33096             });
33097         }
33098         
33099         return cfg;
33100     },
33101     
33102     initEvents: function() 
33103     {
33104         if(this.title.length || this.html.length){
33105             this.el.on('mouseenter'  ,this.enter, this);
33106             this.el.on('mouseleave', this.leave, this);
33107         }
33108         
33109         Roo.EventManager.onWindowResize(this.resize, this); 
33110         
33111         if(this.bgimage.length){
33112             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33113             this.imageEl.on('load', this.onImageLoad, this);
33114             return;
33115         }
33116         
33117         this.resize();
33118     },
33119     
33120     onImageLoad : function()
33121     {
33122         this.resize();
33123     },
33124     
33125     resize : function()
33126     {
33127         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33128         
33129         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33130         
33131         if(this.bgimage.length){
33132             var image = this.el.select('.roo-brick-image-view', true).first();
33133             
33134             image.setWidth(paragraph.getWidth());
33135             
33136             if(this.square){
33137                 image.setHeight(paragraph.getWidth());
33138             }
33139             
33140             this.el.setHeight(image.getHeight());
33141             paragraph.setHeight(image.getHeight());
33142             
33143         }
33144         
33145     },
33146     
33147     enter: function(e, el)
33148     {
33149         e.preventDefault();
33150         
33151         if(this.bgimage.length){
33152             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33153             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33154         }
33155     },
33156     
33157     leave: function(e, el)
33158     {
33159         e.preventDefault();
33160         
33161         if(this.bgimage.length){
33162             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33163             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33164         }
33165     }
33166     
33167 });
33168
33169  
33170
33171  /*
33172  * - LGPL
33173  *
33174  * Number field 
33175  */
33176
33177 /**
33178  * @class Roo.bootstrap.NumberField
33179  * @extends Roo.bootstrap.Input
33180  * Bootstrap NumberField class
33181  * 
33182  * 
33183  * 
33184  * 
33185  * @constructor
33186  * Create a new NumberField
33187  * @param {Object} config The config object
33188  */
33189
33190 Roo.bootstrap.NumberField = function(config){
33191     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33192 };
33193
33194 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33195     
33196     /**
33197      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33198      */
33199     allowDecimals : true,
33200     /**
33201      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33202      */
33203     decimalSeparator : ".",
33204     /**
33205      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33206      */
33207     decimalPrecision : 2,
33208     /**
33209      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33210      */
33211     allowNegative : true,
33212     
33213     /**
33214      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33215      */
33216     allowZero: true,
33217     /**
33218      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33219      */
33220     minValue : Number.NEGATIVE_INFINITY,
33221     /**
33222      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33223      */
33224     maxValue : Number.MAX_VALUE,
33225     /**
33226      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33227      */
33228     minText : "The minimum value for this field is {0}",
33229     /**
33230      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33231      */
33232     maxText : "The maximum value for this field is {0}",
33233     /**
33234      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33235      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33236      */
33237     nanText : "{0} is not a valid number",
33238     /**
33239      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33240      */
33241     thousandsDelimiter : false,
33242     /**
33243      * @cfg {String} valueAlign alignment of value
33244      */
33245     valueAlign : "left",
33246
33247     getAutoCreate : function()
33248     {
33249         var hiddenInput = {
33250             tag: 'input',
33251             type: 'hidden',
33252             id: Roo.id(),
33253             cls: 'hidden-number-input'
33254         };
33255         
33256         if (this.name) {
33257             hiddenInput.name = this.name;
33258         }
33259         
33260         this.name = '';
33261         
33262         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33263         
33264         this.name = hiddenInput.name;
33265         
33266         if(cfg.cn.length > 0) {
33267             cfg.cn.push(hiddenInput);
33268         }
33269         
33270         return cfg;
33271     },
33272
33273     // private
33274     initEvents : function()
33275     {   
33276         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33277         
33278         var allowed = "0123456789";
33279         
33280         if(this.allowDecimals){
33281             allowed += this.decimalSeparator;
33282         }
33283         
33284         if(this.allowNegative){
33285             allowed += "-";
33286         }
33287         
33288         if(this.thousandsDelimiter) {
33289             allowed += ",";
33290         }
33291         
33292         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33293         
33294         var keyPress = function(e){
33295             
33296             var k = e.getKey();
33297             
33298             var c = e.getCharCode();
33299             
33300             if(
33301                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33302                     allowed.indexOf(String.fromCharCode(c)) === -1
33303             ){
33304                 e.stopEvent();
33305                 return;
33306             }
33307             
33308             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33309                 return;
33310             }
33311             
33312             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33313                 e.stopEvent();
33314             }
33315         };
33316         
33317         this.el.on("keypress", keyPress, this);
33318     },
33319     
33320     validateValue : function(value)
33321     {
33322         
33323         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33324             return false;
33325         }
33326         
33327         var num = this.parseValue(value);
33328         
33329         if(isNaN(num)){
33330             this.markInvalid(String.format(this.nanText, value));
33331             return false;
33332         }
33333         
33334         if(num < this.minValue){
33335             this.markInvalid(String.format(this.minText, this.minValue));
33336             return false;
33337         }
33338         
33339         if(num > this.maxValue){
33340             this.markInvalid(String.format(this.maxText, this.maxValue));
33341             return false;
33342         }
33343         
33344         return true;
33345     },
33346
33347     getValue : function()
33348     {
33349         var v = this.hiddenEl().getValue();
33350         
33351         return this.fixPrecision(this.parseValue(v));
33352     },
33353
33354     parseValue : function(value)
33355     {
33356         if(this.thousandsDelimiter) {
33357             value += "";
33358             r = new RegExp(",", "g");
33359             value = value.replace(r, "");
33360         }
33361         
33362         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33363         return isNaN(value) ? '' : value;
33364     },
33365
33366     fixPrecision : function(value)
33367     {
33368         if(this.thousandsDelimiter) {
33369             value += "";
33370             r = new RegExp(",", "g");
33371             value = value.replace(r, "");
33372         }
33373         
33374         var nan = isNaN(value);
33375         
33376         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33377             return nan ? '' : value;
33378         }
33379         return parseFloat(value).toFixed(this.decimalPrecision);
33380     },
33381
33382     setValue : function(v)
33383     {
33384         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33385         
33386         this.value = v;
33387         
33388         if(this.rendered){
33389             
33390             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33391             
33392             this.inputEl().dom.value = (v == '') ? '' :
33393                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33394             
33395             if(!this.allowZero && v === '0') {
33396                 this.hiddenEl().dom.value = '';
33397                 this.inputEl().dom.value = '';
33398             }
33399             
33400             this.validate();
33401         }
33402     },
33403
33404     decimalPrecisionFcn : function(v)
33405     {
33406         return Math.floor(v);
33407     },
33408
33409     beforeBlur : function()
33410     {
33411         var v = this.parseValue(this.getRawValue());
33412         
33413         if(v || v === 0 || v === ''){
33414             this.setValue(v);
33415         }
33416     },
33417     
33418     hiddenEl : function()
33419     {
33420         return this.el.select('input.hidden-number-input',true).first();
33421     }
33422     
33423 });
33424
33425  
33426
33427 /*
33428 * Licence: LGPL
33429 */
33430
33431 /**
33432  * @class Roo.bootstrap.DocumentSlider
33433  * @extends Roo.bootstrap.Component
33434  * Bootstrap DocumentSlider class
33435  * 
33436  * @constructor
33437  * Create a new DocumentViewer
33438  * @param {Object} config The config object
33439  */
33440
33441 Roo.bootstrap.DocumentSlider = function(config){
33442     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33443     
33444     this.files = [];
33445     
33446     this.addEvents({
33447         /**
33448          * @event initial
33449          * Fire after initEvent
33450          * @param {Roo.bootstrap.DocumentSlider} this
33451          */
33452         "initial" : true,
33453         /**
33454          * @event update
33455          * Fire after update
33456          * @param {Roo.bootstrap.DocumentSlider} this
33457          */
33458         "update" : true,
33459         /**
33460          * @event click
33461          * Fire after click
33462          * @param {Roo.bootstrap.DocumentSlider} this
33463          */
33464         "click" : true
33465     });
33466 };
33467
33468 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33469     
33470     files : false,
33471     
33472     indicator : 0,
33473     
33474     getAutoCreate : function()
33475     {
33476         var cfg = {
33477             tag : 'div',
33478             cls : 'roo-document-slider',
33479             cn : [
33480                 {
33481                     tag : 'div',
33482                     cls : 'roo-document-slider-header',
33483                     cn : [
33484                         {
33485                             tag : 'div',
33486                             cls : 'roo-document-slider-header-title'
33487                         }
33488                     ]
33489                 },
33490                 {
33491                     tag : 'div',
33492                     cls : 'roo-document-slider-body',
33493                     cn : [
33494                         {
33495                             tag : 'div',
33496                             cls : 'roo-document-slider-prev',
33497                             cn : [
33498                                 {
33499                                     tag : 'i',
33500                                     cls : 'fa fa-chevron-left'
33501                                 }
33502                             ]
33503                         },
33504                         {
33505                             tag : 'div',
33506                             cls : 'roo-document-slider-thumb',
33507                             cn : [
33508                                 {
33509                                     tag : 'img',
33510                                     cls : 'roo-document-slider-image'
33511                                 }
33512                             ]
33513                         },
33514                         {
33515                             tag : 'div',
33516                             cls : 'roo-document-slider-next',
33517                             cn : [
33518                                 {
33519                                     tag : 'i',
33520                                     cls : 'fa fa-chevron-right'
33521                                 }
33522                             ]
33523                         }
33524                     ]
33525                 }
33526             ]
33527         };
33528         
33529         return cfg;
33530     },
33531     
33532     initEvents : function()
33533     {
33534         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33535         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33536         
33537         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33538         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33539         
33540         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33541         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33542         
33543         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33544         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33545         
33546         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33547         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33548         
33549         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33550         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33551         
33552         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33553         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33554         
33555         this.thumbEl.on('click', this.onClick, this);
33556         
33557         this.prevIndicator.on('click', this.prev, this);
33558         
33559         this.nextIndicator.on('click', this.next, this);
33560         
33561     },
33562     
33563     initial : function()
33564     {
33565         if(this.files.length){
33566             this.indicator = 1;
33567             this.update()
33568         }
33569         
33570         this.fireEvent('initial', this);
33571     },
33572     
33573     update : function()
33574     {
33575         this.imageEl.attr('src', this.files[this.indicator - 1]);
33576         
33577         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33578         
33579         this.prevIndicator.show();
33580         
33581         if(this.indicator == 1){
33582             this.prevIndicator.hide();
33583         }
33584         
33585         this.nextIndicator.show();
33586         
33587         if(this.indicator == this.files.length){
33588             this.nextIndicator.hide();
33589         }
33590         
33591         this.thumbEl.scrollTo('top');
33592         
33593         this.fireEvent('update', this);
33594     },
33595     
33596     onClick : function(e)
33597     {
33598         e.preventDefault();
33599         
33600         this.fireEvent('click', this);
33601     },
33602     
33603     prev : function(e)
33604     {
33605         e.preventDefault();
33606         
33607         this.indicator = Math.max(1, this.indicator - 1);
33608         
33609         this.update();
33610     },
33611     
33612     next : function(e)
33613     {
33614         e.preventDefault();
33615         
33616         this.indicator = Math.min(this.files.length, this.indicator + 1);
33617         
33618         this.update();
33619     }
33620 });
33621 /*
33622  * - LGPL
33623  *
33624  * RadioSet
33625  *
33626  *
33627  */
33628
33629 /**
33630  * @class Roo.bootstrap.RadioSet
33631  * @extends Roo.bootstrap.Input
33632  * Bootstrap RadioSet class
33633  * @cfg {String} indicatorpos (left|right) default left
33634  * @cfg {Boolean} inline (true|false) inline the element (default true)
33635  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33636  * @constructor
33637  * Create a new RadioSet
33638  * @param {Object} config The config object
33639  */
33640
33641 Roo.bootstrap.RadioSet = function(config){
33642     
33643     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33644     
33645     this.radioes = [];
33646     
33647     Roo.bootstrap.RadioSet.register(this);
33648     
33649     this.addEvents({
33650         /**
33651         * @event check
33652         * Fires when the element is checked or unchecked.
33653         * @param {Roo.bootstrap.RadioSet} this This radio
33654         * @param {Roo.bootstrap.Radio} item The checked item
33655         */
33656        check : true,
33657        /**
33658         * @event click
33659         * Fires when the element is click.
33660         * @param {Roo.bootstrap.RadioSet} this This radio set
33661         * @param {Roo.bootstrap.Radio} item The checked item
33662         * @param {Roo.EventObject} e The event object
33663         */
33664        click : true
33665     });
33666     
33667 };
33668
33669 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33670
33671     radioes : false,
33672     
33673     inline : true,
33674     
33675     weight : '',
33676     
33677     indicatorpos : 'left',
33678     
33679     getAutoCreate : function()
33680     {
33681         var label = {
33682             tag : 'label',
33683             cls : 'roo-radio-set-label',
33684             cn : [
33685                 {
33686                     tag : 'span',
33687                     html : this.fieldLabel
33688                 }
33689             ]
33690         };
33691         
33692         if(this.indicatorpos == 'left'){
33693             label.cn.unshift({
33694                 tag : 'i',
33695                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33696                 tooltip : 'This field is required'
33697             });
33698         } else {
33699             label.cn.push({
33700                 tag : 'i',
33701                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33702                 tooltip : 'This field is required'
33703             });
33704         }
33705         
33706         var items = {
33707             tag : 'div',
33708             cls : 'roo-radio-set-items'
33709         };
33710         
33711         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33712         
33713         if (align === 'left' && this.fieldLabel.length) {
33714             
33715             items = {
33716                 cls : "roo-radio-set-right", 
33717                 cn: [
33718                     items
33719                 ]
33720             };
33721             
33722             if(this.labelWidth > 12){
33723                 label.style = "width: " + this.labelWidth + 'px';
33724             }
33725             
33726             if(this.labelWidth < 13 && this.labelmd == 0){
33727                 this.labelmd = this.labelWidth;
33728             }
33729             
33730             if(this.labellg > 0){
33731                 label.cls += ' col-lg-' + this.labellg;
33732                 items.cls += ' col-lg-' + (12 - this.labellg);
33733             }
33734             
33735             if(this.labelmd > 0){
33736                 label.cls += ' col-md-' + this.labelmd;
33737                 items.cls += ' col-md-' + (12 - this.labelmd);
33738             }
33739             
33740             if(this.labelsm > 0){
33741                 label.cls += ' col-sm-' + this.labelsm;
33742                 items.cls += ' col-sm-' + (12 - this.labelsm);
33743             }
33744             
33745             if(this.labelxs > 0){
33746                 label.cls += ' col-xs-' + this.labelxs;
33747                 items.cls += ' col-xs-' + (12 - this.labelxs);
33748             }
33749         }
33750         
33751         var cfg = {
33752             tag : 'div',
33753             cls : 'roo-radio-set',
33754             cn : [
33755                 {
33756                     tag : 'input',
33757                     cls : 'roo-radio-set-input',
33758                     type : 'hidden',
33759                     name : this.name,
33760                     value : this.value ? this.value :  ''
33761                 },
33762                 label,
33763                 items
33764             ]
33765         };
33766         
33767         if(this.weight.length){
33768             cfg.cls += ' roo-radio-' + this.weight;
33769         }
33770         
33771         if(this.inline) {
33772             cfg.cls += ' roo-radio-set-inline';
33773         }
33774         
33775         var settings=this;
33776         ['xs','sm','md','lg'].map(function(size){
33777             if (settings[size]) {
33778                 cfg.cls += ' col-' + size + '-' + settings[size];
33779             }
33780         });
33781         
33782         return cfg;
33783         
33784     },
33785
33786     initEvents : function()
33787     {
33788         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33789         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33790         
33791         if(!this.fieldLabel.length){
33792             this.labelEl.hide();
33793         }
33794         
33795         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33796         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33797         
33798         this.indicator = this.indicatorEl();
33799         
33800         if(this.indicator){
33801             this.indicator.addClass('invisible');
33802         }
33803         
33804         this.originalValue = this.getValue();
33805         
33806     },
33807     
33808     inputEl: function ()
33809     {
33810         return this.el.select('.roo-radio-set-input', true).first();
33811     },
33812     
33813     getChildContainer : function()
33814     {
33815         return this.itemsEl;
33816     },
33817     
33818     register : function(item)
33819     {
33820         this.radioes.push(item);
33821         
33822     },
33823     
33824     validate : function()
33825     {   
33826         if(this.getVisibilityEl().hasClass('hidden')){
33827             return true;
33828         }
33829         
33830         var valid = false;
33831         
33832         Roo.each(this.radioes, function(i){
33833             if(!i.checked){
33834                 return;
33835             }
33836             
33837             valid = true;
33838             return false;
33839         });
33840         
33841         if(this.allowBlank) {
33842             return true;
33843         }
33844         
33845         if(this.disabled || valid){
33846             this.markValid();
33847             return true;
33848         }
33849         
33850         this.markInvalid();
33851         return false;
33852         
33853     },
33854     
33855     markValid : function()
33856     {
33857         if(this.labelEl.isVisible(true)){
33858             this.indicatorEl().removeClass('visible');
33859             this.indicatorEl().addClass('invisible');
33860         }
33861         
33862         this.el.removeClass([this.invalidClass, this.validClass]);
33863         this.el.addClass(this.validClass);
33864         
33865         this.fireEvent('valid', this);
33866     },
33867     
33868     markInvalid : function(msg)
33869     {
33870         if(this.allowBlank || this.disabled){
33871             return;
33872         }
33873         
33874         if(this.labelEl.isVisible(true)){
33875             this.indicatorEl().removeClass('invisible');
33876             this.indicatorEl().addClass('visible');
33877         }
33878         
33879         this.el.removeClass([this.invalidClass, this.validClass]);
33880         this.el.addClass(this.invalidClass);
33881         
33882         this.fireEvent('invalid', this, msg);
33883         
33884     },
33885     
33886     setValue : function(v, suppressEvent)
33887     {   
33888         if(this.value === v){
33889             return;
33890         }
33891         
33892         this.value = v;
33893         
33894         if(this.rendered){
33895             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33896         }
33897         
33898         Roo.each(this.radioes, function(i){
33899             i.checked = false;
33900             i.el.removeClass('checked');
33901         });
33902         
33903         Roo.each(this.radioes, function(i){
33904             
33905             if(i.value === v || i.value.toString() === v.toString()){
33906                 i.checked = true;
33907                 i.el.addClass('checked');
33908                 
33909                 if(suppressEvent !== true){
33910                     this.fireEvent('check', this, i);
33911                 }
33912                 
33913                 return false;
33914             }
33915             
33916         }, this);
33917         
33918         this.validate();
33919     },
33920     
33921     clearInvalid : function(){
33922         
33923         if(!this.el || this.preventMark){
33924             return;
33925         }
33926         
33927         this.el.removeClass([this.invalidClass]);
33928         
33929         this.fireEvent('valid', this);
33930     }
33931     
33932 });
33933
33934 Roo.apply(Roo.bootstrap.RadioSet, {
33935     
33936     groups: {},
33937     
33938     register : function(set)
33939     {
33940         this.groups[set.name] = set;
33941     },
33942     
33943     get: function(name) 
33944     {
33945         if (typeof(this.groups[name]) == 'undefined') {
33946             return false;
33947         }
33948         
33949         return this.groups[name] ;
33950     }
33951     
33952 });
33953 /*
33954  * Based on:
33955  * Ext JS Library 1.1.1
33956  * Copyright(c) 2006-2007, Ext JS, LLC.
33957  *
33958  * Originally Released Under LGPL - original licence link has changed is not relivant.
33959  *
33960  * Fork - LGPL
33961  * <script type="text/javascript">
33962  */
33963
33964
33965 /**
33966  * @class Roo.bootstrap.SplitBar
33967  * @extends Roo.util.Observable
33968  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33969  * <br><br>
33970  * Usage:
33971  * <pre><code>
33972 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33973                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33974 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33975 split.minSize = 100;
33976 split.maxSize = 600;
33977 split.animate = true;
33978 split.on('moved', splitterMoved);
33979 </code></pre>
33980  * @constructor
33981  * Create a new SplitBar
33982  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
33983  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
33984  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33985  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
33986                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33987                         position of the SplitBar).
33988  */
33989 Roo.bootstrap.SplitBar = function(cfg){
33990     
33991     /** @private */
33992     
33993     //{
33994     //  dragElement : elm
33995     //  resizingElement: el,
33996         // optional..
33997     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33998     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
33999         // existingProxy ???
34000     //}
34001     
34002     this.el = Roo.get(cfg.dragElement, true);
34003     this.el.dom.unselectable = "on";
34004     /** @private */
34005     this.resizingEl = Roo.get(cfg.resizingElement, true);
34006
34007     /**
34008      * @private
34009      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34010      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34011      * @type Number
34012      */
34013     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34014     
34015     /**
34016      * The minimum size of the resizing element. (Defaults to 0)
34017      * @type Number
34018      */
34019     this.minSize = 0;
34020     
34021     /**
34022      * The maximum size of the resizing element. (Defaults to 2000)
34023      * @type Number
34024      */
34025     this.maxSize = 2000;
34026     
34027     /**
34028      * Whether to animate the transition to the new size
34029      * @type Boolean
34030      */
34031     this.animate = false;
34032     
34033     /**
34034      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34035      * @type Boolean
34036      */
34037     this.useShim = false;
34038     
34039     /** @private */
34040     this.shim = null;
34041     
34042     if(!cfg.existingProxy){
34043         /** @private */
34044         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34045     }else{
34046         this.proxy = Roo.get(cfg.existingProxy).dom;
34047     }
34048     /** @private */
34049     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34050     
34051     /** @private */
34052     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34053     
34054     /** @private */
34055     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34056     
34057     /** @private */
34058     this.dragSpecs = {};
34059     
34060     /**
34061      * @private The adapter to use to positon and resize elements
34062      */
34063     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34064     this.adapter.init(this);
34065     
34066     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34067         /** @private */
34068         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34069         this.el.addClass("roo-splitbar-h");
34070     }else{
34071         /** @private */
34072         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34073         this.el.addClass("roo-splitbar-v");
34074     }
34075     
34076     this.addEvents({
34077         /**
34078          * @event resize
34079          * Fires when the splitter is moved (alias for {@link #event-moved})
34080          * @param {Roo.bootstrap.SplitBar} this
34081          * @param {Number} newSize the new width or height
34082          */
34083         "resize" : true,
34084         /**
34085          * @event moved
34086          * Fires when the splitter is moved
34087          * @param {Roo.bootstrap.SplitBar} this
34088          * @param {Number} newSize the new width or height
34089          */
34090         "moved" : true,
34091         /**
34092          * @event beforeresize
34093          * Fires before the splitter is dragged
34094          * @param {Roo.bootstrap.SplitBar} this
34095          */
34096         "beforeresize" : true,
34097
34098         "beforeapply" : true
34099     });
34100
34101     Roo.util.Observable.call(this);
34102 };
34103
34104 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34105     onStartProxyDrag : function(x, y){
34106         this.fireEvent("beforeresize", this);
34107         if(!this.overlay){
34108             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
34109             o.unselectable();
34110             o.enableDisplayMode("block");
34111             // all splitbars share the same overlay
34112             Roo.bootstrap.SplitBar.prototype.overlay = o;
34113         }
34114         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34115         this.overlay.show();
34116         Roo.get(this.proxy).setDisplayed("block");
34117         var size = this.adapter.getElementSize(this);
34118         this.activeMinSize = this.getMinimumSize();;
34119         this.activeMaxSize = this.getMaximumSize();;
34120         var c1 = size - this.activeMinSize;
34121         var c2 = Math.max(this.activeMaxSize - size, 0);
34122         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34123             this.dd.resetConstraints();
34124             this.dd.setXConstraint(
34125                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
34126                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34127             );
34128             this.dd.setYConstraint(0, 0);
34129         }else{
34130             this.dd.resetConstraints();
34131             this.dd.setXConstraint(0, 0);
34132             this.dd.setYConstraint(
34133                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
34134                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34135             );
34136          }
34137         this.dragSpecs.startSize = size;
34138         this.dragSpecs.startPoint = [x, y];
34139         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34140     },
34141     
34142     /** 
34143      * @private Called after the drag operation by the DDProxy
34144      */
34145     onEndProxyDrag : function(e){
34146         Roo.get(this.proxy).setDisplayed(false);
34147         var endPoint = Roo.lib.Event.getXY(e);
34148         if(this.overlay){
34149             this.overlay.hide();
34150         }
34151         var newSize;
34152         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34153             newSize = this.dragSpecs.startSize + 
34154                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34155                     endPoint[0] - this.dragSpecs.startPoint[0] :
34156                     this.dragSpecs.startPoint[0] - endPoint[0]
34157                 );
34158         }else{
34159             newSize = this.dragSpecs.startSize + 
34160                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34161                     endPoint[1] - this.dragSpecs.startPoint[1] :
34162                     this.dragSpecs.startPoint[1] - endPoint[1]
34163                 );
34164         }
34165         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34166         if(newSize != this.dragSpecs.startSize){
34167             if(this.fireEvent('beforeapply', this, newSize) !== false){
34168                 this.adapter.setElementSize(this, newSize);
34169                 this.fireEvent("moved", this, newSize);
34170                 this.fireEvent("resize", this, newSize);
34171             }
34172         }
34173     },
34174     
34175     /**
34176      * Get the adapter this SplitBar uses
34177      * @return The adapter object
34178      */
34179     getAdapter : function(){
34180         return this.adapter;
34181     },
34182     
34183     /**
34184      * Set the adapter this SplitBar uses
34185      * @param {Object} adapter A SplitBar adapter object
34186      */
34187     setAdapter : function(adapter){
34188         this.adapter = adapter;
34189         this.adapter.init(this);
34190     },
34191     
34192     /**
34193      * Gets the minimum size for the resizing element
34194      * @return {Number} The minimum size
34195      */
34196     getMinimumSize : function(){
34197         return this.minSize;
34198     },
34199     
34200     /**
34201      * Sets the minimum size for the resizing element
34202      * @param {Number} minSize The minimum size
34203      */
34204     setMinimumSize : function(minSize){
34205         this.minSize = minSize;
34206     },
34207     
34208     /**
34209      * Gets the maximum size for the resizing element
34210      * @return {Number} The maximum size
34211      */
34212     getMaximumSize : function(){
34213         return this.maxSize;
34214     },
34215     
34216     /**
34217      * Sets the maximum size for the resizing element
34218      * @param {Number} maxSize The maximum size
34219      */
34220     setMaximumSize : function(maxSize){
34221         this.maxSize = maxSize;
34222     },
34223     
34224     /**
34225      * Sets the initialize size for the resizing element
34226      * @param {Number} size The initial size
34227      */
34228     setCurrentSize : function(size){
34229         var oldAnimate = this.animate;
34230         this.animate = false;
34231         this.adapter.setElementSize(this, size);
34232         this.animate = oldAnimate;
34233     },
34234     
34235     /**
34236      * Destroy this splitbar. 
34237      * @param {Boolean} removeEl True to remove the element
34238      */
34239     destroy : function(removeEl){
34240         if(this.shim){
34241             this.shim.remove();
34242         }
34243         this.dd.unreg();
34244         this.proxy.parentNode.removeChild(this.proxy);
34245         if(removeEl){
34246             this.el.remove();
34247         }
34248     }
34249 });
34250
34251 /**
34252  * @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.
34253  */
34254 Roo.bootstrap.SplitBar.createProxy = function(dir){
34255     var proxy = new Roo.Element(document.createElement("div"));
34256     proxy.unselectable();
34257     var cls = 'roo-splitbar-proxy';
34258     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34259     document.body.appendChild(proxy.dom);
34260     return proxy.dom;
34261 };
34262
34263 /** 
34264  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34265  * Default Adapter. It assumes the splitter and resizing element are not positioned
34266  * elements and only gets/sets the width of the element. Generally used for table based layouts.
34267  */
34268 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34269 };
34270
34271 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34272     // do nothing for now
34273     init : function(s){
34274     
34275     },
34276     /**
34277      * Called before drag operations to get the current size of the resizing element. 
34278      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34279      */
34280      getElementSize : function(s){
34281         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34282             return s.resizingEl.getWidth();
34283         }else{
34284             return s.resizingEl.getHeight();
34285         }
34286     },
34287     
34288     /**
34289      * Called after drag operations to set the size of the resizing element.
34290      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34291      * @param {Number} newSize The new size to set
34292      * @param {Function} onComplete A function to be invoked when resizing is complete
34293      */
34294     setElementSize : function(s, newSize, onComplete){
34295         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34296             if(!s.animate){
34297                 s.resizingEl.setWidth(newSize);
34298                 if(onComplete){
34299                     onComplete(s, newSize);
34300                 }
34301             }else{
34302                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34303             }
34304         }else{
34305             
34306             if(!s.animate){
34307                 s.resizingEl.setHeight(newSize);
34308                 if(onComplete){
34309                     onComplete(s, newSize);
34310                 }
34311             }else{
34312                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34313             }
34314         }
34315     }
34316 };
34317
34318 /** 
34319  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34320  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34321  * Adapter that  moves the splitter element to align with the resized sizing element. 
34322  * Used with an absolute positioned SplitBar.
34323  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34324  * document.body, make sure you assign an id to the body element.
34325  */
34326 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34327     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34328     this.container = Roo.get(container);
34329 };
34330
34331 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34332     init : function(s){
34333         this.basic.init(s);
34334     },
34335     
34336     getElementSize : function(s){
34337         return this.basic.getElementSize(s);
34338     },
34339     
34340     setElementSize : function(s, newSize, onComplete){
34341         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34342     },
34343     
34344     moveSplitter : function(s){
34345         var yes = Roo.bootstrap.SplitBar;
34346         switch(s.placement){
34347             case yes.LEFT:
34348                 s.el.setX(s.resizingEl.getRight());
34349                 break;
34350             case yes.RIGHT:
34351                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34352                 break;
34353             case yes.TOP:
34354                 s.el.setY(s.resizingEl.getBottom());
34355                 break;
34356             case yes.BOTTOM:
34357                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34358                 break;
34359         }
34360     }
34361 };
34362
34363 /**
34364  * Orientation constant - Create a vertical SplitBar
34365  * @static
34366  * @type Number
34367  */
34368 Roo.bootstrap.SplitBar.VERTICAL = 1;
34369
34370 /**
34371  * Orientation constant - Create a horizontal SplitBar
34372  * @static
34373  * @type Number
34374  */
34375 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34376
34377 /**
34378  * Placement constant - The resizing element is to the left of the splitter element
34379  * @static
34380  * @type Number
34381  */
34382 Roo.bootstrap.SplitBar.LEFT = 1;
34383
34384 /**
34385  * Placement constant - The resizing element is to the right of the splitter element
34386  * @static
34387  * @type Number
34388  */
34389 Roo.bootstrap.SplitBar.RIGHT = 2;
34390
34391 /**
34392  * Placement constant - The resizing element is positioned above the splitter element
34393  * @static
34394  * @type Number
34395  */
34396 Roo.bootstrap.SplitBar.TOP = 3;
34397
34398 /**
34399  * Placement constant - The resizing element is positioned under splitter element
34400  * @static
34401  * @type Number
34402  */
34403 Roo.bootstrap.SplitBar.BOTTOM = 4;
34404 Roo.namespace("Roo.bootstrap.layout");/*
34405  * Based on:
34406  * Ext JS Library 1.1.1
34407  * Copyright(c) 2006-2007, Ext JS, LLC.
34408  *
34409  * Originally Released Under LGPL - original licence link has changed is not relivant.
34410  *
34411  * Fork - LGPL
34412  * <script type="text/javascript">
34413  */
34414
34415 /**
34416  * @class Roo.bootstrap.layout.Manager
34417  * @extends Roo.bootstrap.Component
34418  * Base class for layout managers.
34419  */
34420 Roo.bootstrap.layout.Manager = function(config)
34421 {
34422     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34423
34424
34425
34426
34427
34428     /** false to disable window resize monitoring @type Boolean */
34429     this.monitorWindowResize = true;
34430     this.regions = {};
34431     this.addEvents({
34432         /**
34433          * @event layout
34434          * Fires when a layout is performed.
34435          * @param {Roo.LayoutManager} this
34436          */
34437         "layout" : true,
34438         /**
34439          * @event regionresized
34440          * Fires when the user resizes a region.
34441          * @param {Roo.LayoutRegion} region The resized region
34442          * @param {Number} newSize The new size (width for east/west, height for north/south)
34443          */
34444         "regionresized" : true,
34445         /**
34446          * @event regioncollapsed
34447          * Fires when a region is collapsed.
34448          * @param {Roo.LayoutRegion} region The collapsed region
34449          */
34450         "regioncollapsed" : true,
34451         /**
34452          * @event regionexpanded
34453          * Fires when a region is expanded.
34454          * @param {Roo.LayoutRegion} region The expanded region
34455          */
34456         "regionexpanded" : true
34457     });
34458     this.updating = false;
34459
34460     if (config.el) {
34461         this.el = Roo.get(config.el);
34462         this.initEvents();
34463     }
34464
34465 };
34466
34467 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34468
34469
34470     regions : null,
34471
34472     monitorWindowResize : true,
34473
34474
34475     updating : false,
34476
34477
34478     onRender : function(ct, position)
34479     {
34480         if(!this.el){
34481             this.el = Roo.get(ct);
34482             this.initEvents();
34483         }
34484         //this.fireEvent('render',this);
34485     },
34486
34487
34488     initEvents: function()
34489     {
34490
34491
34492         // ie scrollbar fix
34493         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34494             document.body.scroll = "no";
34495         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34496             this.el.position('relative');
34497         }
34498         this.id = this.el.id;
34499         this.el.addClass("roo-layout-container");
34500         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34501         if(this.el.dom != document.body ) {
34502             this.el.on('resize', this.layout,this);
34503             this.el.on('show', this.layout,this);
34504         }
34505
34506     },
34507
34508     /**
34509      * Returns true if this layout is currently being updated
34510      * @return {Boolean}
34511      */
34512     isUpdating : function(){
34513         return this.updating;
34514     },
34515
34516     /**
34517      * Suspend the LayoutManager from doing auto-layouts while
34518      * making multiple add or remove calls
34519      */
34520     beginUpdate : function(){
34521         this.updating = true;
34522     },
34523
34524     /**
34525      * Restore auto-layouts and optionally disable the manager from performing a layout
34526      * @param {Boolean} noLayout true to disable a layout update
34527      */
34528     endUpdate : function(noLayout){
34529         this.updating = false;
34530         if(!noLayout){
34531             this.layout();
34532         }
34533     },
34534
34535     layout: function(){
34536         // abstract...
34537     },
34538
34539     onRegionResized : function(region, newSize){
34540         this.fireEvent("regionresized", region, newSize);
34541         this.layout();
34542     },
34543
34544     onRegionCollapsed : function(region){
34545         this.fireEvent("regioncollapsed", region);
34546     },
34547
34548     onRegionExpanded : function(region){
34549         this.fireEvent("regionexpanded", region);
34550     },
34551
34552     /**
34553      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34554      * performs box-model adjustments.
34555      * @return {Object} The size as an object {width: (the width), height: (the height)}
34556      */
34557     getViewSize : function()
34558     {
34559         var size;
34560         if(this.el.dom != document.body){
34561             size = this.el.getSize();
34562         }else{
34563             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34564         }
34565         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34566         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34567         return size;
34568     },
34569
34570     /**
34571      * Returns the Element this layout is bound to.
34572      * @return {Roo.Element}
34573      */
34574     getEl : function(){
34575         return this.el;
34576     },
34577
34578     /**
34579      * Returns the specified region.
34580      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34581      * @return {Roo.LayoutRegion}
34582      */
34583     getRegion : function(target){
34584         return this.regions[target.toLowerCase()];
34585     },
34586
34587     onWindowResize : function(){
34588         if(this.monitorWindowResize){
34589             this.layout();
34590         }
34591     }
34592 });
34593 /*
34594  * Based on:
34595  * Ext JS Library 1.1.1
34596  * Copyright(c) 2006-2007, Ext JS, LLC.
34597  *
34598  * Originally Released Under LGPL - original licence link has changed is not relivant.
34599  *
34600  * Fork - LGPL
34601  * <script type="text/javascript">
34602  */
34603 /**
34604  * @class Roo.bootstrap.layout.Border
34605  * @extends Roo.bootstrap.layout.Manager
34606  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34607  * please see: examples/bootstrap/nested.html<br><br>
34608  
34609 <b>The container the layout is rendered into can be either the body element or any other element.
34610 If it is not the body element, the container needs to either be an absolute positioned element,
34611 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34612 the container size if it is not the body element.</b>
34613
34614 * @constructor
34615 * Create a new Border
34616 * @param {Object} config Configuration options
34617  */
34618 Roo.bootstrap.layout.Border = function(config){
34619     config = config || {};
34620     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34621     
34622     
34623     
34624     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34625         if(config[region]){
34626             config[region].region = region;
34627             this.addRegion(config[region]);
34628         }
34629     },this);
34630     
34631 };
34632
34633 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34634
34635 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34636     /**
34637      * Creates and adds a new region if it doesn't already exist.
34638      * @param {String} target The target region key (north, south, east, west or center).
34639      * @param {Object} config The regions config object
34640      * @return {BorderLayoutRegion} The new region
34641      */
34642     addRegion : function(config)
34643     {
34644         if(!this.regions[config.region]){
34645             var r = this.factory(config);
34646             this.bindRegion(r);
34647         }
34648         return this.regions[config.region];
34649     },
34650
34651     // private (kinda)
34652     bindRegion : function(r){
34653         this.regions[r.config.region] = r;
34654         
34655         r.on("visibilitychange",    this.layout, this);
34656         r.on("paneladded",          this.layout, this);
34657         r.on("panelremoved",        this.layout, this);
34658         r.on("invalidated",         this.layout, this);
34659         r.on("resized",             this.onRegionResized, this);
34660         r.on("collapsed",           this.onRegionCollapsed, this);
34661         r.on("expanded",            this.onRegionExpanded, this);
34662     },
34663
34664     /**
34665      * Performs a layout update.
34666      */
34667     layout : function()
34668     {
34669         if(this.updating) {
34670             return;
34671         }
34672         
34673         // render all the rebions if they have not been done alreayd?
34674         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34675             if(this.regions[region] && !this.regions[region].bodyEl){
34676                 this.regions[region].onRender(this.el)
34677             }
34678         },this);
34679         
34680         var size = this.getViewSize();
34681         var w = size.width;
34682         var h = size.height;
34683         var centerW = w;
34684         var centerH = h;
34685         var centerY = 0;
34686         var centerX = 0;
34687         //var x = 0, y = 0;
34688
34689         var rs = this.regions;
34690         var north = rs["north"];
34691         var south = rs["south"]; 
34692         var west = rs["west"];
34693         var east = rs["east"];
34694         var center = rs["center"];
34695         //if(this.hideOnLayout){ // not supported anymore
34696             //c.el.setStyle("display", "none");
34697         //}
34698         if(north && north.isVisible()){
34699             var b = north.getBox();
34700             var m = north.getMargins();
34701             b.width = w - (m.left+m.right);
34702             b.x = m.left;
34703             b.y = m.top;
34704             centerY = b.height + b.y + m.bottom;
34705             centerH -= centerY;
34706             north.updateBox(this.safeBox(b));
34707         }
34708         if(south && south.isVisible()){
34709             var b = south.getBox();
34710             var m = south.getMargins();
34711             b.width = w - (m.left+m.right);
34712             b.x = m.left;
34713             var totalHeight = (b.height + m.top + m.bottom);
34714             b.y = h - totalHeight + m.top;
34715             centerH -= totalHeight;
34716             south.updateBox(this.safeBox(b));
34717         }
34718         if(west && west.isVisible()){
34719             var b = west.getBox();
34720             var m = west.getMargins();
34721             b.height = centerH - (m.top+m.bottom);
34722             b.x = m.left;
34723             b.y = centerY + m.top;
34724             var totalWidth = (b.width + m.left + m.right);
34725             centerX += totalWidth;
34726             centerW -= totalWidth;
34727             west.updateBox(this.safeBox(b));
34728         }
34729         if(east && east.isVisible()){
34730             var b = east.getBox();
34731             var m = east.getMargins();
34732             b.height = centerH - (m.top+m.bottom);
34733             var totalWidth = (b.width + m.left + m.right);
34734             b.x = w - totalWidth + m.left;
34735             b.y = centerY + m.top;
34736             centerW -= totalWidth;
34737             east.updateBox(this.safeBox(b));
34738         }
34739         if(center){
34740             var m = center.getMargins();
34741             var centerBox = {
34742                 x: centerX + m.left,
34743                 y: centerY + m.top,
34744                 width: centerW - (m.left+m.right),
34745                 height: centerH - (m.top+m.bottom)
34746             };
34747             //if(this.hideOnLayout){
34748                 //center.el.setStyle("display", "block");
34749             //}
34750             center.updateBox(this.safeBox(centerBox));
34751         }
34752         this.el.repaint();
34753         this.fireEvent("layout", this);
34754     },
34755
34756     // private
34757     safeBox : function(box){
34758         box.width = Math.max(0, box.width);
34759         box.height = Math.max(0, box.height);
34760         return box;
34761     },
34762
34763     /**
34764      * Adds a ContentPanel (or subclass) to this layout.
34765      * @param {String} target The target region key (north, south, east, west or center).
34766      * @param {Roo.ContentPanel} panel The panel to add
34767      * @return {Roo.ContentPanel} The added panel
34768      */
34769     add : function(target, panel){
34770          
34771         target = target.toLowerCase();
34772         return this.regions[target].add(panel);
34773     },
34774
34775     /**
34776      * Remove a ContentPanel (or subclass) to this layout.
34777      * @param {String} target The target region key (north, south, east, west or center).
34778      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34779      * @return {Roo.ContentPanel} The removed panel
34780      */
34781     remove : function(target, panel){
34782         target = target.toLowerCase();
34783         return this.regions[target].remove(panel);
34784     },
34785
34786     /**
34787      * Searches all regions for a panel with the specified id
34788      * @param {String} panelId
34789      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34790      */
34791     findPanel : function(panelId){
34792         var rs = this.regions;
34793         for(var target in rs){
34794             if(typeof rs[target] != "function"){
34795                 var p = rs[target].getPanel(panelId);
34796                 if(p){
34797                     return p;
34798                 }
34799             }
34800         }
34801         return null;
34802     },
34803
34804     /**
34805      * Searches all regions for a panel with the specified id and activates (shows) it.
34806      * @param {String/ContentPanel} panelId The panels id or the panel itself
34807      * @return {Roo.ContentPanel} The shown panel or null
34808      */
34809     showPanel : function(panelId) {
34810       var rs = this.regions;
34811       for(var target in rs){
34812          var r = rs[target];
34813          if(typeof r != "function"){
34814             if(r.hasPanel(panelId)){
34815                return r.showPanel(panelId);
34816             }
34817          }
34818       }
34819       return null;
34820    },
34821
34822    /**
34823      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34824      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34825      */
34826    /*
34827     restoreState : function(provider){
34828         if(!provider){
34829             provider = Roo.state.Manager;
34830         }
34831         var sm = new Roo.LayoutStateManager();
34832         sm.init(this, provider);
34833     },
34834 */
34835  
34836  
34837     /**
34838      * Adds a xtype elements to the layout.
34839      * <pre><code>
34840
34841 layout.addxtype({
34842        xtype : 'ContentPanel',
34843        region: 'west',
34844        items: [ .... ]
34845    }
34846 );
34847
34848 layout.addxtype({
34849         xtype : 'NestedLayoutPanel',
34850         region: 'west',
34851         layout: {
34852            center: { },
34853            west: { }   
34854         },
34855         items : [ ... list of content panels or nested layout panels.. ]
34856    }
34857 );
34858 </code></pre>
34859      * @param {Object} cfg Xtype definition of item to add.
34860      */
34861     addxtype : function(cfg)
34862     {
34863         // basically accepts a pannel...
34864         // can accept a layout region..!?!?
34865         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34866         
34867         
34868         // theory?  children can only be panels??
34869         
34870         //if (!cfg.xtype.match(/Panel$/)) {
34871         //    return false;
34872         //}
34873         var ret = false;
34874         
34875         if (typeof(cfg.region) == 'undefined') {
34876             Roo.log("Failed to add Panel, region was not set");
34877             Roo.log(cfg);
34878             return false;
34879         }
34880         var region = cfg.region;
34881         delete cfg.region;
34882         
34883           
34884         var xitems = [];
34885         if (cfg.items) {
34886             xitems = cfg.items;
34887             delete cfg.items;
34888         }
34889         var nb = false;
34890         
34891         switch(cfg.xtype) 
34892         {
34893             case 'Content':  // ContentPanel (el, cfg)
34894             case 'Scroll':  // ContentPanel (el, cfg)
34895             case 'View': 
34896                 cfg.autoCreate = true;
34897                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34898                 //} else {
34899                 //    var el = this.el.createChild();
34900                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34901                 //}
34902                 
34903                 this.add(region, ret);
34904                 break;
34905             
34906             /*
34907             case 'TreePanel': // our new panel!
34908                 cfg.el = this.el.createChild();
34909                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34910                 this.add(region, ret);
34911                 break;
34912             */
34913             
34914             case 'Nest': 
34915                 // create a new Layout (which is  a Border Layout...
34916                 
34917                 var clayout = cfg.layout;
34918                 clayout.el  = this.el.createChild();
34919                 clayout.items   = clayout.items  || [];
34920                 
34921                 delete cfg.layout;
34922                 
34923                 // replace this exitems with the clayout ones..
34924                 xitems = clayout.items;
34925                  
34926                 // force background off if it's in center...
34927                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34928                     cfg.background = false;
34929                 }
34930                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34931                 
34932                 
34933                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34934                 //console.log('adding nested layout panel '  + cfg.toSource());
34935                 this.add(region, ret);
34936                 nb = {}; /// find first...
34937                 break;
34938             
34939             case 'Grid':
34940                 
34941                 // needs grid and region
34942                 
34943                 //var el = this.getRegion(region).el.createChild();
34944                 /*
34945                  *var el = this.el.createChild();
34946                 // create the grid first...
34947                 cfg.grid.container = el;
34948                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34949                 */
34950                 
34951                 if (region == 'center' && this.active ) {
34952                     cfg.background = false;
34953                 }
34954                 
34955                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34956                 
34957                 this.add(region, ret);
34958                 /*
34959                 if (cfg.background) {
34960                     // render grid on panel activation (if panel background)
34961                     ret.on('activate', function(gp) {
34962                         if (!gp.grid.rendered) {
34963                     //        gp.grid.render(el);
34964                         }
34965                     });
34966                 } else {
34967                   //  cfg.grid.render(el);
34968                 }
34969                 */
34970                 break;
34971            
34972            
34973             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34974                 // it was the old xcomponent building that caused this before.
34975                 // espeically if border is the top element in the tree.
34976                 ret = this;
34977                 break; 
34978                 
34979                     
34980                 
34981                 
34982                 
34983             default:
34984                 /*
34985                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34986                     
34987                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34988                     this.add(region, ret);
34989                 } else {
34990                 */
34991                     Roo.log(cfg);
34992                     throw "Can not add '" + cfg.xtype + "' to Border";
34993                     return null;
34994              
34995                                 
34996              
34997         }
34998         this.beginUpdate();
34999         // add children..
35000         var region = '';
35001         var abn = {};
35002         Roo.each(xitems, function(i)  {
35003             region = nb && i.region ? i.region : false;
35004             
35005             var add = ret.addxtype(i);
35006            
35007             if (region) {
35008                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35009                 if (!i.background) {
35010                     abn[region] = nb[region] ;
35011                 }
35012             }
35013             
35014         });
35015         this.endUpdate();
35016
35017         // make the last non-background panel active..
35018         //if (nb) { Roo.log(abn); }
35019         if (nb) {
35020             
35021             for(var r in abn) {
35022                 region = this.getRegion(r);
35023                 if (region) {
35024                     // tried using nb[r], but it does not work..
35025                      
35026                     region.showPanel(abn[r]);
35027                    
35028                 }
35029             }
35030         }
35031         return ret;
35032         
35033     },
35034     
35035     
35036 // private
35037     factory : function(cfg)
35038     {
35039         
35040         var validRegions = Roo.bootstrap.layout.Border.regions;
35041
35042         var target = cfg.region;
35043         cfg.mgr = this;
35044         
35045         var r = Roo.bootstrap.layout;
35046         Roo.log(target);
35047         switch(target){
35048             case "north":
35049                 return new r.North(cfg);
35050             case "south":
35051                 return new r.South(cfg);
35052             case "east":
35053                 return new r.East(cfg);
35054             case "west":
35055                 return new r.West(cfg);
35056             case "center":
35057                 return new r.Center(cfg);
35058         }
35059         throw 'Layout region "'+target+'" not supported.';
35060     }
35061     
35062     
35063 });
35064  /*
35065  * Based on:
35066  * Ext JS Library 1.1.1
35067  * Copyright(c) 2006-2007, Ext JS, LLC.
35068  *
35069  * Originally Released Under LGPL - original licence link has changed is not relivant.
35070  *
35071  * Fork - LGPL
35072  * <script type="text/javascript">
35073  */
35074  
35075 /**
35076  * @class Roo.bootstrap.layout.Basic
35077  * @extends Roo.util.Observable
35078  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35079  * and does not have a titlebar, tabs or any other features. All it does is size and position 
35080  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35081  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35082  * @cfg {string}   region  the region that it inhabits..
35083  * @cfg {bool}   skipConfig skip config?
35084  * 
35085
35086  */
35087 Roo.bootstrap.layout.Basic = function(config){
35088     
35089     this.mgr = config.mgr;
35090     
35091     this.position = config.region;
35092     
35093     var skipConfig = config.skipConfig;
35094     
35095     this.events = {
35096         /**
35097          * @scope Roo.BasicLayoutRegion
35098          */
35099         
35100         /**
35101          * @event beforeremove
35102          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35103          * @param {Roo.LayoutRegion} this
35104          * @param {Roo.ContentPanel} panel The panel
35105          * @param {Object} e The cancel event object
35106          */
35107         "beforeremove" : true,
35108         /**
35109          * @event invalidated
35110          * Fires when the layout for this region is changed.
35111          * @param {Roo.LayoutRegion} this
35112          */
35113         "invalidated" : true,
35114         /**
35115          * @event visibilitychange
35116          * Fires when this region is shown or hidden 
35117          * @param {Roo.LayoutRegion} this
35118          * @param {Boolean} visibility true or false
35119          */
35120         "visibilitychange" : true,
35121         /**
35122          * @event paneladded
35123          * Fires when a panel is added. 
35124          * @param {Roo.LayoutRegion} this
35125          * @param {Roo.ContentPanel} panel The panel
35126          */
35127         "paneladded" : true,
35128         /**
35129          * @event panelremoved
35130          * Fires when a panel is removed. 
35131          * @param {Roo.LayoutRegion} this
35132          * @param {Roo.ContentPanel} panel The panel
35133          */
35134         "panelremoved" : true,
35135         /**
35136          * @event beforecollapse
35137          * Fires when this region before collapse.
35138          * @param {Roo.LayoutRegion} this
35139          */
35140         "beforecollapse" : true,
35141         /**
35142          * @event collapsed
35143          * Fires when this region is collapsed.
35144          * @param {Roo.LayoutRegion} this
35145          */
35146         "collapsed" : true,
35147         /**
35148          * @event expanded
35149          * Fires when this region is expanded.
35150          * @param {Roo.LayoutRegion} this
35151          */
35152         "expanded" : true,
35153         /**
35154          * @event slideshow
35155          * Fires when this region is slid into view.
35156          * @param {Roo.LayoutRegion} this
35157          */
35158         "slideshow" : true,
35159         /**
35160          * @event slidehide
35161          * Fires when this region slides out of view. 
35162          * @param {Roo.LayoutRegion} this
35163          */
35164         "slidehide" : true,
35165         /**
35166          * @event panelactivated
35167          * Fires when a panel is activated. 
35168          * @param {Roo.LayoutRegion} this
35169          * @param {Roo.ContentPanel} panel The activated panel
35170          */
35171         "panelactivated" : true,
35172         /**
35173          * @event resized
35174          * Fires when the user resizes this region. 
35175          * @param {Roo.LayoutRegion} this
35176          * @param {Number} newSize The new size (width for east/west, height for north/south)
35177          */
35178         "resized" : true
35179     };
35180     /** A collection of panels in this region. @type Roo.util.MixedCollection */
35181     this.panels = new Roo.util.MixedCollection();
35182     this.panels.getKey = this.getPanelId.createDelegate(this);
35183     this.box = null;
35184     this.activePanel = null;
35185     // ensure listeners are added...
35186     
35187     if (config.listeners || config.events) {
35188         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35189             listeners : config.listeners || {},
35190             events : config.events || {}
35191         });
35192     }
35193     
35194     if(skipConfig !== true){
35195         this.applyConfig(config);
35196     }
35197 };
35198
35199 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35200 {
35201     getPanelId : function(p){
35202         return p.getId();
35203     },
35204     
35205     applyConfig : function(config){
35206         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35207         this.config = config;
35208         
35209     },
35210     
35211     /**
35212      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
35213      * the width, for horizontal (north, south) the height.
35214      * @param {Number} newSize The new width or height
35215      */
35216     resizeTo : function(newSize){
35217         var el = this.el ? this.el :
35218                  (this.activePanel ? this.activePanel.getEl() : null);
35219         if(el){
35220             switch(this.position){
35221                 case "east":
35222                 case "west":
35223                     el.setWidth(newSize);
35224                     this.fireEvent("resized", this, newSize);
35225                 break;
35226                 case "north":
35227                 case "south":
35228                     el.setHeight(newSize);
35229                     this.fireEvent("resized", this, newSize);
35230                 break;                
35231             }
35232         }
35233     },
35234     
35235     getBox : function(){
35236         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35237     },
35238     
35239     getMargins : function(){
35240         return this.margins;
35241     },
35242     
35243     updateBox : function(box){
35244         this.box = box;
35245         var el = this.activePanel.getEl();
35246         el.dom.style.left = box.x + "px";
35247         el.dom.style.top = box.y + "px";
35248         this.activePanel.setSize(box.width, box.height);
35249     },
35250     
35251     /**
35252      * Returns the container element for this region.
35253      * @return {Roo.Element}
35254      */
35255     getEl : function(){
35256         return this.activePanel;
35257     },
35258     
35259     /**
35260      * Returns true if this region is currently visible.
35261      * @return {Boolean}
35262      */
35263     isVisible : function(){
35264         return this.activePanel ? true : false;
35265     },
35266     
35267     setActivePanel : function(panel){
35268         panel = this.getPanel(panel);
35269         if(this.activePanel && this.activePanel != panel){
35270             this.activePanel.setActiveState(false);
35271             this.activePanel.getEl().setLeftTop(-10000,-10000);
35272         }
35273         this.activePanel = panel;
35274         panel.setActiveState(true);
35275         if(this.box){
35276             panel.setSize(this.box.width, this.box.height);
35277         }
35278         this.fireEvent("panelactivated", this, panel);
35279         this.fireEvent("invalidated");
35280     },
35281     
35282     /**
35283      * Show the specified panel.
35284      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35285      * @return {Roo.ContentPanel} The shown panel or null
35286      */
35287     showPanel : function(panel){
35288         panel = this.getPanel(panel);
35289         if(panel){
35290             this.setActivePanel(panel);
35291         }
35292         return panel;
35293     },
35294     
35295     /**
35296      * Get the active panel for this region.
35297      * @return {Roo.ContentPanel} The active panel or null
35298      */
35299     getActivePanel : function(){
35300         return this.activePanel;
35301     },
35302     
35303     /**
35304      * Add the passed ContentPanel(s)
35305      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35306      * @return {Roo.ContentPanel} The panel added (if only one was added)
35307      */
35308     add : function(panel){
35309         if(arguments.length > 1){
35310             for(var i = 0, len = arguments.length; i < len; i++) {
35311                 this.add(arguments[i]);
35312             }
35313             return null;
35314         }
35315         if(this.hasPanel(panel)){
35316             this.showPanel(panel);
35317             return panel;
35318         }
35319         var el = panel.getEl();
35320         if(el.dom.parentNode != this.mgr.el.dom){
35321             this.mgr.el.dom.appendChild(el.dom);
35322         }
35323         if(panel.setRegion){
35324             panel.setRegion(this);
35325         }
35326         this.panels.add(panel);
35327         el.setStyle("position", "absolute");
35328         if(!panel.background){
35329             this.setActivePanel(panel);
35330             if(this.config.initialSize && this.panels.getCount()==1){
35331                 this.resizeTo(this.config.initialSize);
35332             }
35333         }
35334         this.fireEvent("paneladded", this, panel);
35335         return panel;
35336     },
35337     
35338     /**
35339      * Returns true if the panel is in this region.
35340      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35341      * @return {Boolean}
35342      */
35343     hasPanel : function(panel){
35344         if(typeof panel == "object"){ // must be panel obj
35345             panel = panel.getId();
35346         }
35347         return this.getPanel(panel) ? true : false;
35348     },
35349     
35350     /**
35351      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35352      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35353      * @param {Boolean} preservePanel Overrides the config preservePanel option
35354      * @return {Roo.ContentPanel} The panel that was removed
35355      */
35356     remove : function(panel, preservePanel){
35357         panel = this.getPanel(panel);
35358         if(!panel){
35359             return null;
35360         }
35361         var e = {};
35362         this.fireEvent("beforeremove", this, panel, e);
35363         if(e.cancel === true){
35364             return null;
35365         }
35366         var panelId = panel.getId();
35367         this.panels.removeKey(panelId);
35368         return panel;
35369     },
35370     
35371     /**
35372      * Returns the panel specified or null if it's not in this region.
35373      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35374      * @return {Roo.ContentPanel}
35375      */
35376     getPanel : function(id){
35377         if(typeof id == "object"){ // must be panel obj
35378             return id;
35379         }
35380         return this.panels.get(id);
35381     },
35382     
35383     /**
35384      * Returns this regions position (north/south/east/west/center).
35385      * @return {String} 
35386      */
35387     getPosition: function(){
35388         return this.position;    
35389     }
35390 });/*
35391  * Based on:
35392  * Ext JS Library 1.1.1
35393  * Copyright(c) 2006-2007, Ext JS, LLC.
35394  *
35395  * Originally Released Under LGPL - original licence link has changed is not relivant.
35396  *
35397  * Fork - LGPL
35398  * <script type="text/javascript">
35399  */
35400  
35401 /**
35402  * @class Roo.bootstrap.layout.Region
35403  * @extends Roo.bootstrap.layout.Basic
35404  * This class represents a region in a layout manager.
35405  
35406  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35407  * @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})
35408  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35409  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35410  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35411  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35412  * @cfg {String}    title           The title for the region (overrides panel titles)
35413  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35414  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35415  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35416  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35417  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35418  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35419  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35420  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35421  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35422  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35423
35424  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35425  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35426  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35427  * @cfg {Number}    width           For East/West panels
35428  * @cfg {Number}    height          For North/South panels
35429  * @cfg {Boolean}   split           To show the splitter
35430  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35431  * 
35432  * @cfg {string}   cls             Extra CSS classes to add to region
35433  * 
35434  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35435  * @cfg {string}   region  the region that it inhabits..
35436  *
35437
35438  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35439  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35440
35441  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35442  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35443  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35444  */
35445 Roo.bootstrap.layout.Region = function(config)
35446 {
35447     this.applyConfig(config);
35448
35449     var mgr = config.mgr;
35450     var pos = config.region;
35451     config.skipConfig = true;
35452     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35453     
35454     if (mgr.el) {
35455         this.onRender(mgr.el);   
35456     }
35457      
35458     this.visible = true;
35459     this.collapsed = false;
35460     this.unrendered_panels = [];
35461 };
35462
35463 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35464
35465     position: '', // set by wrapper (eg. north/south etc..)
35466     unrendered_panels : null,  // unrendered panels.
35467     createBody : function(){
35468         /** This region's body element 
35469         * @type Roo.Element */
35470         this.bodyEl = this.el.createChild({
35471                 tag: "div",
35472                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35473         });
35474     },
35475
35476     onRender: function(ctr, pos)
35477     {
35478         var dh = Roo.DomHelper;
35479         /** This region's container element 
35480         * @type Roo.Element */
35481         this.el = dh.append(ctr.dom, {
35482                 tag: "div",
35483                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35484             }, true);
35485         /** This region's title element 
35486         * @type Roo.Element */
35487     
35488         this.titleEl = dh.append(this.el.dom,
35489             {
35490                     tag: "div",
35491                     unselectable: "on",
35492                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35493                     children:[
35494                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35495                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35496                     ]}, true);
35497         
35498         this.titleEl.enableDisplayMode();
35499         /** This region's title text element 
35500         * @type HTMLElement */
35501         this.titleTextEl = this.titleEl.dom.firstChild;
35502         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35503         /*
35504         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35505         this.closeBtn.enableDisplayMode();
35506         this.closeBtn.on("click", this.closeClicked, this);
35507         this.closeBtn.hide();
35508     */
35509         this.createBody(this.config);
35510         if(this.config.hideWhenEmpty){
35511             this.hide();
35512             this.on("paneladded", this.validateVisibility, this);
35513             this.on("panelremoved", this.validateVisibility, this);
35514         }
35515         if(this.autoScroll){
35516             this.bodyEl.setStyle("overflow", "auto");
35517         }else{
35518             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35519         }
35520         //if(c.titlebar !== false){
35521             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35522                 this.titleEl.hide();
35523             }else{
35524                 this.titleEl.show();
35525                 if(this.config.title){
35526                     this.titleTextEl.innerHTML = this.config.title;
35527                 }
35528             }
35529         //}
35530         if(this.config.collapsed){
35531             this.collapse(true);
35532         }
35533         if(this.config.hidden){
35534             this.hide();
35535         }
35536         
35537         if (this.unrendered_panels && this.unrendered_panels.length) {
35538             for (var i =0;i< this.unrendered_panels.length; i++) {
35539                 this.add(this.unrendered_panels[i]);
35540             }
35541             this.unrendered_panels = null;
35542             
35543         }
35544         
35545     },
35546     
35547     applyConfig : function(c)
35548     {
35549         /*
35550          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35551             var dh = Roo.DomHelper;
35552             if(c.titlebar !== false){
35553                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35554                 this.collapseBtn.on("click", this.collapse, this);
35555                 this.collapseBtn.enableDisplayMode();
35556                 /*
35557                 if(c.showPin === true || this.showPin){
35558                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35559                     this.stickBtn.enableDisplayMode();
35560                     this.stickBtn.on("click", this.expand, this);
35561                     this.stickBtn.hide();
35562                 }
35563                 
35564             }
35565             */
35566             /** This region's collapsed element
35567             * @type Roo.Element */
35568             /*
35569              *
35570             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35571                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35572             ]}, true);
35573             
35574             if(c.floatable !== false){
35575                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35576                this.collapsedEl.on("click", this.collapseClick, this);
35577             }
35578
35579             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35580                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35581                    id: "message", unselectable: "on", style:{"float":"left"}});
35582                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35583              }
35584             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35585             this.expandBtn.on("click", this.expand, this);
35586             
35587         }
35588         
35589         if(this.collapseBtn){
35590             this.collapseBtn.setVisible(c.collapsible == true);
35591         }
35592         
35593         this.cmargins = c.cmargins || this.cmargins ||
35594                          (this.position == "west" || this.position == "east" ?
35595                              {top: 0, left: 2, right:2, bottom: 0} :
35596                              {top: 2, left: 0, right:0, bottom: 2});
35597         */
35598         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35599         
35600         
35601         this.bottomTabs = c.tabPosition != "top";
35602         
35603         this.autoScroll = c.autoScroll || false;
35604         
35605         
35606        
35607         
35608         this.duration = c.duration || .30;
35609         this.slideDuration = c.slideDuration || .45;
35610         this.config = c;
35611        
35612     },
35613     /**
35614      * Returns true if this region is currently visible.
35615      * @return {Boolean}
35616      */
35617     isVisible : function(){
35618         return this.visible;
35619     },
35620
35621     /**
35622      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35623      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35624      */
35625     //setCollapsedTitle : function(title){
35626     //    title = title || "&#160;";
35627      //   if(this.collapsedTitleTextEl){
35628       //      this.collapsedTitleTextEl.innerHTML = title;
35629        // }
35630     //},
35631
35632     getBox : function(){
35633         var b;
35634       //  if(!this.collapsed){
35635             b = this.el.getBox(false, true);
35636        // }else{
35637           //  b = this.collapsedEl.getBox(false, true);
35638         //}
35639         return b;
35640     },
35641
35642     getMargins : function(){
35643         return this.margins;
35644         //return this.collapsed ? this.cmargins : this.margins;
35645     },
35646 /*
35647     highlight : function(){
35648         this.el.addClass("x-layout-panel-dragover");
35649     },
35650
35651     unhighlight : function(){
35652         this.el.removeClass("x-layout-panel-dragover");
35653     },
35654 */
35655     updateBox : function(box)
35656     {
35657         if (!this.bodyEl) {
35658             return; // not rendered yet..
35659         }
35660         
35661         this.box = box;
35662         if(!this.collapsed){
35663             this.el.dom.style.left = box.x + "px";
35664             this.el.dom.style.top = box.y + "px";
35665             this.updateBody(box.width, box.height);
35666         }else{
35667             this.collapsedEl.dom.style.left = box.x + "px";
35668             this.collapsedEl.dom.style.top = box.y + "px";
35669             this.collapsedEl.setSize(box.width, box.height);
35670         }
35671         if(this.tabs){
35672             this.tabs.autoSizeTabs();
35673         }
35674     },
35675
35676     updateBody : function(w, h)
35677     {
35678         if(w !== null){
35679             this.el.setWidth(w);
35680             w -= this.el.getBorderWidth("rl");
35681             if(this.config.adjustments){
35682                 w += this.config.adjustments[0];
35683             }
35684         }
35685         if(h !== null && h > 0){
35686             this.el.setHeight(h);
35687             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35688             h -= this.el.getBorderWidth("tb");
35689             if(this.config.adjustments){
35690                 h += this.config.adjustments[1];
35691             }
35692             this.bodyEl.setHeight(h);
35693             if(this.tabs){
35694                 h = this.tabs.syncHeight(h);
35695             }
35696         }
35697         if(this.panelSize){
35698             w = w !== null ? w : this.panelSize.width;
35699             h = h !== null ? h : this.panelSize.height;
35700         }
35701         if(this.activePanel){
35702             var el = this.activePanel.getEl();
35703             w = w !== null ? w : el.getWidth();
35704             h = h !== null ? h : el.getHeight();
35705             this.panelSize = {width: w, height: h};
35706             this.activePanel.setSize(w, h);
35707         }
35708         if(Roo.isIE && this.tabs){
35709             this.tabs.el.repaint();
35710         }
35711     },
35712
35713     /**
35714      * Returns the container element for this region.
35715      * @return {Roo.Element}
35716      */
35717     getEl : function(){
35718         return this.el;
35719     },
35720
35721     /**
35722      * Hides this region.
35723      */
35724     hide : function(){
35725         //if(!this.collapsed){
35726             this.el.dom.style.left = "-2000px";
35727             this.el.hide();
35728         //}else{
35729          //   this.collapsedEl.dom.style.left = "-2000px";
35730          //   this.collapsedEl.hide();
35731        // }
35732         this.visible = false;
35733         this.fireEvent("visibilitychange", this, false);
35734     },
35735
35736     /**
35737      * Shows this region if it was previously hidden.
35738      */
35739     show : function(){
35740         //if(!this.collapsed){
35741             this.el.show();
35742         //}else{
35743         //    this.collapsedEl.show();
35744        // }
35745         this.visible = true;
35746         this.fireEvent("visibilitychange", this, true);
35747     },
35748 /*
35749     closeClicked : function(){
35750         if(this.activePanel){
35751             this.remove(this.activePanel);
35752         }
35753     },
35754
35755     collapseClick : function(e){
35756         if(this.isSlid){
35757            e.stopPropagation();
35758            this.slideIn();
35759         }else{
35760            e.stopPropagation();
35761            this.slideOut();
35762         }
35763     },
35764 */
35765     /**
35766      * Collapses this region.
35767      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35768      */
35769     /*
35770     collapse : function(skipAnim, skipCheck = false){
35771         if(this.collapsed) {
35772             return;
35773         }
35774         
35775         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35776             
35777             this.collapsed = true;
35778             if(this.split){
35779                 this.split.el.hide();
35780             }
35781             if(this.config.animate && skipAnim !== true){
35782                 this.fireEvent("invalidated", this);
35783                 this.animateCollapse();
35784             }else{
35785                 this.el.setLocation(-20000,-20000);
35786                 this.el.hide();
35787                 this.collapsedEl.show();
35788                 this.fireEvent("collapsed", this);
35789                 this.fireEvent("invalidated", this);
35790             }
35791         }
35792         
35793     },
35794 */
35795     animateCollapse : function(){
35796         // overridden
35797     },
35798
35799     /**
35800      * Expands this region if it was previously collapsed.
35801      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35802      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35803      */
35804     /*
35805     expand : function(e, skipAnim){
35806         if(e) {
35807             e.stopPropagation();
35808         }
35809         if(!this.collapsed || this.el.hasActiveFx()) {
35810             return;
35811         }
35812         if(this.isSlid){
35813             this.afterSlideIn();
35814             skipAnim = true;
35815         }
35816         this.collapsed = false;
35817         if(this.config.animate && skipAnim !== true){
35818             this.animateExpand();
35819         }else{
35820             this.el.show();
35821             if(this.split){
35822                 this.split.el.show();
35823             }
35824             this.collapsedEl.setLocation(-2000,-2000);
35825             this.collapsedEl.hide();
35826             this.fireEvent("invalidated", this);
35827             this.fireEvent("expanded", this);
35828         }
35829     },
35830 */
35831     animateExpand : function(){
35832         // overridden
35833     },
35834
35835     initTabs : function()
35836     {
35837         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35838         
35839         var ts = new Roo.bootstrap.panel.Tabs({
35840                 el: this.bodyEl.dom,
35841                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35842                 disableTooltips: this.config.disableTabTips,
35843                 toolbar : this.config.toolbar
35844             });
35845         
35846         if(this.config.hideTabs){
35847             ts.stripWrap.setDisplayed(false);
35848         }
35849         this.tabs = ts;
35850         ts.resizeTabs = this.config.resizeTabs === true;
35851         ts.minTabWidth = this.config.minTabWidth || 40;
35852         ts.maxTabWidth = this.config.maxTabWidth || 250;
35853         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35854         ts.monitorResize = false;
35855         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35856         ts.bodyEl.addClass('roo-layout-tabs-body');
35857         this.panels.each(this.initPanelAsTab, this);
35858     },
35859
35860     initPanelAsTab : function(panel){
35861         var ti = this.tabs.addTab(
35862             panel.getEl().id,
35863             panel.getTitle(),
35864             null,
35865             this.config.closeOnTab && panel.isClosable(),
35866             panel.tpl
35867         );
35868         if(panel.tabTip !== undefined){
35869             ti.setTooltip(panel.tabTip);
35870         }
35871         ti.on("activate", function(){
35872               this.setActivePanel(panel);
35873         }, this);
35874         
35875         if(this.config.closeOnTab){
35876             ti.on("beforeclose", function(t, e){
35877                 e.cancel = true;
35878                 this.remove(panel);
35879             }, this);
35880         }
35881         
35882         panel.tabItem = ti;
35883         
35884         return ti;
35885     },
35886
35887     updatePanelTitle : function(panel, title)
35888     {
35889         if(this.activePanel == panel){
35890             this.updateTitle(title);
35891         }
35892         if(this.tabs){
35893             var ti = this.tabs.getTab(panel.getEl().id);
35894             ti.setText(title);
35895             if(panel.tabTip !== undefined){
35896                 ti.setTooltip(panel.tabTip);
35897             }
35898         }
35899     },
35900
35901     updateTitle : function(title){
35902         if(this.titleTextEl && !this.config.title){
35903             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35904         }
35905     },
35906
35907     setActivePanel : function(panel)
35908     {
35909         panel = this.getPanel(panel);
35910         if(this.activePanel && this.activePanel != panel){
35911             if(this.activePanel.setActiveState(false) === false){
35912                 return;
35913             }
35914         }
35915         this.activePanel = panel;
35916         panel.setActiveState(true);
35917         if(this.panelSize){
35918             panel.setSize(this.panelSize.width, this.panelSize.height);
35919         }
35920         if(this.closeBtn){
35921             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35922         }
35923         this.updateTitle(panel.getTitle());
35924         if(this.tabs){
35925             this.fireEvent("invalidated", this);
35926         }
35927         this.fireEvent("panelactivated", this, panel);
35928     },
35929
35930     /**
35931      * Shows the specified panel.
35932      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35933      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35934      */
35935     showPanel : function(panel)
35936     {
35937         panel = this.getPanel(panel);
35938         if(panel){
35939             if(this.tabs){
35940                 var tab = this.tabs.getTab(panel.getEl().id);
35941                 if(tab.isHidden()){
35942                     this.tabs.unhideTab(tab.id);
35943                 }
35944                 tab.activate();
35945             }else{
35946                 this.setActivePanel(panel);
35947             }
35948         }
35949         return panel;
35950     },
35951
35952     /**
35953      * Get the active panel for this region.
35954      * @return {Roo.ContentPanel} The active panel or null
35955      */
35956     getActivePanel : function(){
35957         return this.activePanel;
35958     },
35959
35960     validateVisibility : function(){
35961         if(this.panels.getCount() < 1){
35962             this.updateTitle("&#160;");
35963             this.closeBtn.hide();
35964             this.hide();
35965         }else{
35966             if(!this.isVisible()){
35967                 this.show();
35968             }
35969         }
35970     },
35971
35972     /**
35973      * Adds the passed ContentPanel(s) to this region.
35974      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35975      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35976      */
35977     add : function(panel)
35978     {
35979         if(arguments.length > 1){
35980             for(var i = 0, len = arguments.length; i < len; i++) {
35981                 this.add(arguments[i]);
35982             }
35983             return null;
35984         }
35985         
35986         // if we have not been rendered yet, then we can not really do much of this..
35987         if (!this.bodyEl) {
35988             this.unrendered_panels.push(panel);
35989             return panel;
35990         }
35991         
35992         
35993         
35994         
35995         if(this.hasPanel(panel)){
35996             this.showPanel(panel);
35997             return panel;
35998         }
35999         panel.setRegion(this);
36000         this.panels.add(panel);
36001        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36002             // sinle panel - no tab...?? would it not be better to render it with the tabs,
36003             // and hide them... ???
36004             this.bodyEl.dom.appendChild(panel.getEl().dom);
36005             if(panel.background !== true){
36006                 this.setActivePanel(panel);
36007             }
36008             this.fireEvent("paneladded", this, panel);
36009             return panel;
36010         }
36011         */
36012         if(!this.tabs){
36013             this.initTabs();
36014         }else{
36015             this.initPanelAsTab(panel);
36016         }
36017         
36018         
36019         if(panel.background !== true){
36020             this.tabs.activate(panel.getEl().id);
36021         }
36022         this.fireEvent("paneladded", this, panel);
36023         return panel;
36024     },
36025
36026     /**
36027      * Hides the tab for the specified panel.
36028      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36029      */
36030     hidePanel : function(panel){
36031         if(this.tabs && (panel = this.getPanel(panel))){
36032             this.tabs.hideTab(panel.getEl().id);
36033         }
36034     },
36035
36036     /**
36037      * Unhides the tab for a previously hidden panel.
36038      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36039      */
36040     unhidePanel : function(panel){
36041         if(this.tabs && (panel = this.getPanel(panel))){
36042             this.tabs.unhideTab(panel.getEl().id);
36043         }
36044     },
36045
36046     clearPanels : function(){
36047         while(this.panels.getCount() > 0){
36048              this.remove(this.panels.first());
36049         }
36050     },
36051
36052     /**
36053      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36054      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36055      * @param {Boolean} preservePanel Overrides the config preservePanel option
36056      * @return {Roo.ContentPanel} The panel that was removed
36057      */
36058     remove : function(panel, preservePanel)
36059     {
36060         panel = this.getPanel(panel);
36061         if(!panel){
36062             return null;
36063         }
36064         var e = {};
36065         this.fireEvent("beforeremove", this, panel, e);
36066         if(e.cancel === true){
36067             return null;
36068         }
36069         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36070         var panelId = panel.getId();
36071         this.panels.removeKey(panelId);
36072         if(preservePanel){
36073             document.body.appendChild(panel.getEl().dom);
36074         }
36075         if(this.tabs){
36076             this.tabs.removeTab(panel.getEl().id);
36077         }else if (!preservePanel){
36078             this.bodyEl.dom.removeChild(panel.getEl().dom);
36079         }
36080         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36081             var p = this.panels.first();
36082             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36083             tempEl.appendChild(p.getEl().dom);
36084             this.bodyEl.update("");
36085             this.bodyEl.dom.appendChild(p.getEl().dom);
36086             tempEl = null;
36087             this.updateTitle(p.getTitle());
36088             this.tabs = null;
36089             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36090             this.setActivePanel(p);
36091         }
36092         panel.setRegion(null);
36093         if(this.activePanel == panel){
36094             this.activePanel = null;
36095         }
36096         if(this.config.autoDestroy !== false && preservePanel !== true){
36097             try{panel.destroy();}catch(e){}
36098         }
36099         this.fireEvent("panelremoved", this, panel);
36100         return panel;
36101     },
36102
36103     /**
36104      * Returns the TabPanel component used by this region
36105      * @return {Roo.TabPanel}
36106      */
36107     getTabs : function(){
36108         return this.tabs;
36109     },
36110
36111     createTool : function(parentEl, className){
36112         var btn = Roo.DomHelper.append(parentEl, {
36113             tag: "div",
36114             cls: "x-layout-tools-button",
36115             children: [ {
36116                 tag: "div",
36117                 cls: "roo-layout-tools-button-inner " + className,
36118                 html: "&#160;"
36119             }]
36120         }, true);
36121         btn.addClassOnOver("roo-layout-tools-button-over");
36122         return btn;
36123     }
36124 });/*
36125  * Based on:
36126  * Ext JS Library 1.1.1
36127  * Copyright(c) 2006-2007, Ext JS, LLC.
36128  *
36129  * Originally Released Under LGPL - original licence link has changed is not relivant.
36130  *
36131  * Fork - LGPL
36132  * <script type="text/javascript">
36133  */
36134  
36135
36136
36137 /**
36138  * @class Roo.SplitLayoutRegion
36139  * @extends Roo.LayoutRegion
36140  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36141  */
36142 Roo.bootstrap.layout.Split = function(config){
36143     this.cursor = config.cursor;
36144     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36145 };
36146
36147 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36148 {
36149     splitTip : "Drag to resize.",
36150     collapsibleSplitTip : "Drag to resize. Double click to hide.",
36151     useSplitTips : false,
36152
36153     applyConfig : function(config){
36154         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36155     },
36156     
36157     onRender : function(ctr,pos) {
36158         
36159         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36160         if(!this.config.split){
36161             return;
36162         }
36163         if(!this.split){
36164             
36165             var splitEl = Roo.DomHelper.append(ctr.dom,  {
36166                             tag: "div",
36167                             id: this.el.id + "-split",
36168                             cls: "roo-layout-split roo-layout-split-"+this.position,
36169                             html: "&#160;"
36170             });
36171             /** The SplitBar for this region 
36172             * @type Roo.SplitBar */
36173             // does not exist yet...
36174             Roo.log([this.position, this.orientation]);
36175             
36176             this.split = new Roo.bootstrap.SplitBar({
36177                 dragElement : splitEl,
36178                 resizingElement: this.el,
36179                 orientation : this.orientation
36180             });
36181             
36182             this.split.on("moved", this.onSplitMove, this);
36183             this.split.useShim = this.config.useShim === true;
36184             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36185             if(this.useSplitTips){
36186                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36187             }
36188             //if(config.collapsible){
36189             //    this.split.el.on("dblclick", this.collapse,  this);
36190             //}
36191         }
36192         if(typeof this.config.minSize != "undefined"){
36193             this.split.minSize = this.config.minSize;
36194         }
36195         if(typeof this.config.maxSize != "undefined"){
36196             this.split.maxSize = this.config.maxSize;
36197         }
36198         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36199             this.hideSplitter();
36200         }
36201         
36202     },
36203
36204     getHMaxSize : function(){
36205          var cmax = this.config.maxSize || 10000;
36206          var center = this.mgr.getRegion("center");
36207          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36208     },
36209
36210     getVMaxSize : function(){
36211          var cmax = this.config.maxSize || 10000;
36212          var center = this.mgr.getRegion("center");
36213          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36214     },
36215
36216     onSplitMove : function(split, newSize){
36217         this.fireEvent("resized", this, newSize);
36218     },
36219     
36220     /** 
36221      * Returns the {@link Roo.SplitBar} for this region.
36222      * @return {Roo.SplitBar}
36223      */
36224     getSplitBar : function(){
36225         return this.split;
36226     },
36227     
36228     hide : function(){
36229         this.hideSplitter();
36230         Roo.bootstrap.layout.Split.superclass.hide.call(this);
36231     },
36232
36233     hideSplitter : function(){
36234         if(this.split){
36235             this.split.el.setLocation(-2000,-2000);
36236             this.split.el.hide();
36237         }
36238     },
36239
36240     show : function(){
36241         if(this.split){
36242             this.split.el.show();
36243         }
36244         Roo.bootstrap.layout.Split.superclass.show.call(this);
36245     },
36246     
36247     beforeSlide: function(){
36248         if(Roo.isGecko){// firefox overflow auto bug workaround
36249             this.bodyEl.clip();
36250             if(this.tabs) {
36251                 this.tabs.bodyEl.clip();
36252             }
36253             if(this.activePanel){
36254                 this.activePanel.getEl().clip();
36255                 
36256                 if(this.activePanel.beforeSlide){
36257                     this.activePanel.beforeSlide();
36258                 }
36259             }
36260         }
36261     },
36262     
36263     afterSlide : function(){
36264         if(Roo.isGecko){// firefox overflow auto bug workaround
36265             this.bodyEl.unclip();
36266             if(this.tabs) {
36267                 this.tabs.bodyEl.unclip();
36268             }
36269             if(this.activePanel){
36270                 this.activePanel.getEl().unclip();
36271                 if(this.activePanel.afterSlide){
36272                     this.activePanel.afterSlide();
36273                 }
36274             }
36275         }
36276     },
36277
36278     initAutoHide : function(){
36279         if(this.autoHide !== false){
36280             if(!this.autoHideHd){
36281                 var st = new Roo.util.DelayedTask(this.slideIn, this);
36282                 this.autoHideHd = {
36283                     "mouseout": function(e){
36284                         if(!e.within(this.el, true)){
36285                             st.delay(500);
36286                         }
36287                     },
36288                     "mouseover" : function(e){
36289                         st.cancel();
36290                     },
36291                     scope : this
36292                 };
36293             }
36294             this.el.on(this.autoHideHd);
36295         }
36296     },
36297
36298     clearAutoHide : function(){
36299         if(this.autoHide !== false){
36300             this.el.un("mouseout", this.autoHideHd.mouseout);
36301             this.el.un("mouseover", this.autoHideHd.mouseover);
36302         }
36303     },
36304
36305     clearMonitor : function(){
36306         Roo.get(document).un("click", this.slideInIf, this);
36307     },
36308
36309     // these names are backwards but not changed for compat
36310     slideOut : function(){
36311         if(this.isSlid || this.el.hasActiveFx()){
36312             return;
36313         }
36314         this.isSlid = true;
36315         if(this.collapseBtn){
36316             this.collapseBtn.hide();
36317         }
36318         this.closeBtnState = this.closeBtn.getStyle('display');
36319         this.closeBtn.hide();
36320         if(this.stickBtn){
36321             this.stickBtn.show();
36322         }
36323         this.el.show();
36324         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36325         this.beforeSlide();
36326         this.el.setStyle("z-index", 10001);
36327         this.el.slideIn(this.getSlideAnchor(), {
36328             callback: function(){
36329                 this.afterSlide();
36330                 this.initAutoHide();
36331                 Roo.get(document).on("click", this.slideInIf, this);
36332                 this.fireEvent("slideshow", this);
36333             },
36334             scope: this,
36335             block: true
36336         });
36337     },
36338
36339     afterSlideIn : function(){
36340         this.clearAutoHide();
36341         this.isSlid = false;
36342         this.clearMonitor();
36343         this.el.setStyle("z-index", "");
36344         if(this.collapseBtn){
36345             this.collapseBtn.show();
36346         }
36347         this.closeBtn.setStyle('display', this.closeBtnState);
36348         if(this.stickBtn){
36349             this.stickBtn.hide();
36350         }
36351         this.fireEvent("slidehide", this);
36352     },
36353
36354     slideIn : function(cb){
36355         if(!this.isSlid || this.el.hasActiveFx()){
36356             Roo.callback(cb);
36357             return;
36358         }
36359         this.isSlid = false;
36360         this.beforeSlide();
36361         this.el.slideOut(this.getSlideAnchor(), {
36362             callback: function(){
36363                 this.el.setLeftTop(-10000, -10000);
36364                 this.afterSlide();
36365                 this.afterSlideIn();
36366                 Roo.callback(cb);
36367             },
36368             scope: this,
36369             block: true
36370         });
36371     },
36372     
36373     slideInIf : function(e){
36374         if(!e.within(this.el)){
36375             this.slideIn();
36376         }
36377     },
36378
36379     animateCollapse : function(){
36380         this.beforeSlide();
36381         this.el.setStyle("z-index", 20000);
36382         var anchor = this.getSlideAnchor();
36383         this.el.slideOut(anchor, {
36384             callback : function(){
36385                 this.el.setStyle("z-index", "");
36386                 this.collapsedEl.slideIn(anchor, {duration:.3});
36387                 this.afterSlide();
36388                 this.el.setLocation(-10000,-10000);
36389                 this.el.hide();
36390                 this.fireEvent("collapsed", this);
36391             },
36392             scope: this,
36393             block: true
36394         });
36395     },
36396
36397     animateExpand : function(){
36398         this.beforeSlide();
36399         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36400         this.el.setStyle("z-index", 20000);
36401         this.collapsedEl.hide({
36402             duration:.1
36403         });
36404         this.el.slideIn(this.getSlideAnchor(), {
36405             callback : function(){
36406                 this.el.setStyle("z-index", "");
36407                 this.afterSlide();
36408                 if(this.split){
36409                     this.split.el.show();
36410                 }
36411                 this.fireEvent("invalidated", this);
36412                 this.fireEvent("expanded", this);
36413             },
36414             scope: this,
36415             block: true
36416         });
36417     },
36418
36419     anchors : {
36420         "west" : "left",
36421         "east" : "right",
36422         "north" : "top",
36423         "south" : "bottom"
36424     },
36425
36426     sanchors : {
36427         "west" : "l",
36428         "east" : "r",
36429         "north" : "t",
36430         "south" : "b"
36431     },
36432
36433     canchors : {
36434         "west" : "tl-tr",
36435         "east" : "tr-tl",
36436         "north" : "tl-bl",
36437         "south" : "bl-tl"
36438     },
36439
36440     getAnchor : function(){
36441         return this.anchors[this.position];
36442     },
36443
36444     getCollapseAnchor : function(){
36445         return this.canchors[this.position];
36446     },
36447
36448     getSlideAnchor : function(){
36449         return this.sanchors[this.position];
36450     },
36451
36452     getAlignAdj : function(){
36453         var cm = this.cmargins;
36454         switch(this.position){
36455             case "west":
36456                 return [0, 0];
36457             break;
36458             case "east":
36459                 return [0, 0];
36460             break;
36461             case "north":
36462                 return [0, 0];
36463             break;
36464             case "south":
36465                 return [0, 0];
36466             break;
36467         }
36468     },
36469
36470     getExpandAdj : function(){
36471         var c = this.collapsedEl, cm = this.cmargins;
36472         switch(this.position){
36473             case "west":
36474                 return [-(cm.right+c.getWidth()+cm.left), 0];
36475             break;
36476             case "east":
36477                 return [cm.right+c.getWidth()+cm.left, 0];
36478             break;
36479             case "north":
36480                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36481             break;
36482             case "south":
36483                 return [0, cm.top+cm.bottom+c.getHeight()];
36484             break;
36485         }
36486     }
36487 });/*
36488  * Based on:
36489  * Ext JS Library 1.1.1
36490  * Copyright(c) 2006-2007, Ext JS, LLC.
36491  *
36492  * Originally Released Under LGPL - original licence link has changed is not relivant.
36493  *
36494  * Fork - LGPL
36495  * <script type="text/javascript">
36496  */
36497 /*
36498  * These classes are private internal classes
36499  */
36500 Roo.bootstrap.layout.Center = function(config){
36501     config.region = "center";
36502     Roo.bootstrap.layout.Region.call(this, config);
36503     this.visible = true;
36504     this.minWidth = config.minWidth || 20;
36505     this.minHeight = config.minHeight || 20;
36506 };
36507
36508 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36509     hide : function(){
36510         // center panel can't be hidden
36511     },
36512     
36513     show : function(){
36514         // center panel can't be hidden
36515     },
36516     
36517     getMinWidth: function(){
36518         return this.minWidth;
36519     },
36520     
36521     getMinHeight: function(){
36522         return this.minHeight;
36523     }
36524 });
36525
36526
36527
36528
36529  
36530
36531
36532
36533
36534
36535 Roo.bootstrap.layout.North = function(config)
36536 {
36537     config.region = 'north';
36538     config.cursor = 'n-resize';
36539     
36540     Roo.bootstrap.layout.Split.call(this, config);
36541     
36542     
36543     if(this.split){
36544         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36545         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36546         this.split.el.addClass("roo-layout-split-v");
36547     }
36548     var size = config.initialSize || config.height;
36549     if(typeof size != "undefined"){
36550         this.el.setHeight(size);
36551     }
36552 };
36553 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36554 {
36555     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36556     
36557     
36558     
36559     getBox : function(){
36560         if(this.collapsed){
36561             return this.collapsedEl.getBox();
36562         }
36563         var box = this.el.getBox();
36564         if(this.split){
36565             box.height += this.split.el.getHeight();
36566         }
36567         return box;
36568     },
36569     
36570     updateBox : function(box){
36571         if(this.split && !this.collapsed){
36572             box.height -= this.split.el.getHeight();
36573             this.split.el.setLeft(box.x);
36574             this.split.el.setTop(box.y+box.height);
36575             this.split.el.setWidth(box.width);
36576         }
36577         if(this.collapsed){
36578             this.updateBody(box.width, null);
36579         }
36580         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36581     }
36582 });
36583
36584
36585
36586
36587
36588 Roo.bootstrap.layout.South = function(config){
36589     config.region = 'south';
36590     config.cursor = 's-resize';
36591     Roo.bootstrap.layout.Split.call(this, config);
36592     if(this.split){
36593         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36594         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36595         this.split.el.addClass("roo-layout-split-v");
36596     }
36597     var size = config.initialSize || config.height;
36598     if(typeof size != "undefined"){
36599         this.el.setHeight(size);
36600     }
36601 };
36602
36603 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36604     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36605     getBox : function(){
36606         if(this.collapsed){
36607             return this.collapsedEl.getBox();
36608         }
36609         var box = this.el.getBox();
36610         if(this.split){
36611             var sh = this.split.el.getHeight();
36612             box.height += sh;
36613             box.y -= sh;
36614         }
36615         return box;
36616     },
36617     
36618     updateBox : function(box){
36619         if(this.split && !this.collapsed){
36620             var sh = this.split.el.getHeight();
36621             box.height -= sh;
36622             box.y += sh;
36623             this.split.el.setLeft(box.x);
36624             this.split.el.setTop(box.y-sh);
36625             this.split.el.setWidth(box.width);
36626         }
36627         if(this.collapsed){
36628             this.updateBody(box.width, null);
36629         }
36630         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36631     }
36632 });
36633
36634 Roo.bootstrap.layout.East = function(config){
36635     config.region = "east";
36636     config.cursor = "e-resize";
36637     Roo.bootstrap.layout.Split.call(this, config);
36638     if(this.split){
36639         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36640         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36641         this.split.el.addClass("roo-layout-split-h");
36642     }
36643     var size = config.initialSize || config.width;
36644     if(typeof size != "undefined"){
36645         this.el.setWidth(size);
36646     }
36647 };
36648 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36649     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36650     getBox : function(){
36651         if(this.collapsed){
36652             return this.collapsedEl.getBox();
36653         }
36654         var box = this.el.getBox();
36655         if(this.split){
36656             var sw = this.split.el.getWidth();
36657             box.width += sw;
36658             box.x -= sw;
36659         }
36660         return box;
36661     },
36662
36663     updateBox : function(box){
36664         if(this.split && !this.collapsed){
36665             var sw = this.split.el.getWidth();
36666             box.width -= sw;
36667             this.split.el.setLeft(box.x);
36668             this.split.el.setTop(box.y);
36669             this.split.el.setHeight(box.height);
36670             box.x += sw;
36671         }
36672         if(this.collapsed){
36673             this.updateBody(null, box.height);
36674         }
36675         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36676     }
36677 });
36678
36679 Roo.bootstrap.layout.West = function(config){
36680     config.region = "west";
36681     config.cursor = "w-resize";
36682     
36683     Roo.bootstrap.layout.Split.call(this, config);
36684     if(this.split){
36685         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36686         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36687         this.split.el.addClass("roo-layout-split-h");
36688     }
36689     
36690 };
36691 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36692     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36693     
36694     onRender: function(ctr, pos)
36695     {
36696         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36697         var size = this.config.initialSize || this.config.width;
36698         if(typeof size != "undefined"){
36699             this.el.setWidth(size);
36700         }
36701     },
36702     
36703     getBox : function(){
36704         if(this.collapsed){
36705             return this.collapsedEl.getBox();
36706         }
36707         var box = this.el.getBox();
36708         if(this.split){
36709             box.width += this.split.el.getWidth();
36710         }
36711         return box;
36712     },
36713     
36714     updateBox : function(box){
36715         if(this.split && !this.collapsed){
36716             var sw = this.split.el.getWidth();
36717             box.width -= sw;
36718             this.split.el.setLeft(box.x+box.width);
36719             this.split.el.setTop(box.y);
36720             this.split.el.setHeight(box.height);
36721         }
36722         if(this.collapsed){
36723             this.updateBody(null, box.height);
36724         }
36725         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36726     }
36727 });
36728 Roo.namespace("Roo.bootstrap.panel");/*
36729  * Based on:
36730  * Ext JS Library 1.1.1
36731  * Copyright(c) 2006-2007, Ext JS, LLC.
36732  *
36733  * Originally Released Under LGPL - original licence link has changed is not relivant.
36734  *
36735  * Fork - LGPL
36736  * <script type="text/javascript">
36737  */
36738 /**
36739  * @class Roo.ContentPanel
36740  * @extends Roo.util.Observable
36741  * A basic ContentPanel element.
36742  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36743  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36744  * @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
36745  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36746  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36747  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36748  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36749  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36750  * @cfg {String} title          The title for this panel
36751  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36752  * @cfg {String} url            Calls {@link #setUrl} with this value
36753  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36754  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36755  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36756  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36757  * @cfg {Boolean} badges render the badges
36758
36759  * @constructor
36760  * Create a new ContentPanel.
36761  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36762  * @param {String/Object} config A string to set only the title or a config object
36763  * @param {String} content (optional) Set the HTML content for this panel
36764  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36765  */
36766 Roo.bootstrap.panel.Content = function( config){
36767     
36768     this.tpl = config.tpl || false;
36769     
36770     var el = config.el;
36771     var content = config.content;
36772
36773     if(config.autoCreate){ // xtype is available if this is called from factory
36774         el = Roo.id();
36775     }
36776     this.el = Roo.get(el);
36777     if(!this.el && config && config.autoCreate){
36778         if(typeof config.autoCreate == "object"){
36779             if(!config.autoCreate.id){
36780                 config.autoCreate.id = config.id||el;
36781             }
36782             this.el = Roo.DomHelper.append(document.body,
36783                         config.autoCreate, true);
36784         }else{
36785             var elcfg =  {   tag: "div",
36786                             cls: "roo-layout-inactive-content",
36787                             id: config.id||el
36788                             };
36789             if (config.html) {
36790                 elcfg.html = config.html;
36791                 
36792             }
36793                         
36794             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36795         }
36796     } 
36797     this.closable = false;
36798     this.loaded = false;
36799     this.active = false;
36800    
36801       
36802     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36803         
36804         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36805         
36806         this.wrapEl = this.el; //this.el.wrap();
36807         var ti = [];
36808         if (config.toolbar.items) {
36809             ti = config.toolbar.items ;
36810             delete config.toolbar.items ;
36811         }
36812         
36813         var nitems = [];
36814         this.toolbar.render(this.wrapEl, 'before');
36815         for(var i =0;i < ti.length;i++) {
36816           //  Roo.log(['add child', items[i]]);
36817             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36818         }
36819         this.toolbar.items = nitems;
36820         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36821         delete config.toolbar;
36822         
36823     }
36824     /*
36825     // xtype created footer. - not sure if will work as we normally have to render first..
36826     if (this.footer && !this.footer.el && this.footer.xtype) {
36827         if (!this.wrapEl) {
36828             this.wrapEl = this.el.wrap();
36829         }
36830     
36831         this.footer.container = this.wrapEl.createChild();
36832          
36833         this.footer = Roo.factory(this.footer, Roo);
36834         
36835     }
36836     */
36837     
36838      if(typeof config == "string"){
36839         this.title = config;
36840     }else{
36841         Roo.apply(this, config);
36842     }
36843     
36844     if(this.resizeEl){
36845         this.resizeEl = Roo.get(this.resizeEl, true);
36846     }else{
36847         this.resizeEl = this.el;
36848     }
36849     // handle view.xtype
36850     
36851  
36852     
36853     
36854     this.addEvents({
36855         /**
36856          * @event activate
36857          * Fires when this panel is activated. 
36858          * @param {Roo.ContentPanel} this
36859          */
36860         "activate" : true,
36861         /**
36862          * @event deactivate
36863          * Fires when this panel is activated. 
36864          * @param {Roo.ContentPanel} this
36865          */
36866         "deactivate" : true,
36867
36868         /**
36869          * @event resize
36870          * Fires when this panel is resized if fitToFrame is true.
36871          * @param {Roo.ContentPanel} this
36872          * @param {Number} width The width after any component adjustments
36873          * @param {Number} height The height after any component adjustments
36874          */
36875         "resize" : true,
36876         
36877          /**
36878          * @event render
36879          * Fires when this tab is created
36880          * @param {Roo.ContentPanel} this
36881          */
36882         "render" : true
36883         
36884         
36885         
36886     });
36887     
36888
36889     
36890     
36891     if(this.autoScroll){
36892         this.resizeEl.setStyle("overflow", "auto");
36893     } else {
36894         // fix randome scrolling
36895         //this.el.on('scroll', function() {
36896         //    Roo.log('fix random scolling');
36897         //    this.scrollTo('top',0); 
36898         //});
36899     }
36900     content = content || this.content;
36901     if(content){
36902         this.setContent(content);
36903     }
36904     if(config && config.url){
36905         this.setUrl(this.url, this.params, this.loadOnce);
36906     }
36907     
36908     
36909     
36910     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36911     
36912     if (this.view && typeof(this.view.xtype) != 'undefined') {
36913         this.view.el = this.el.appendChild(document.createElement("div"));
36914         this.view = Roo.factory(this.view); 
36915         this.view.render  &&  this.view.render(false, '');  
36916     }
36917     
36918     
36919     this.fireEvent('render', this);
36920 };
36921
36922 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36923     
36924     tabTip : '',
36925     
36926     setRegion : function(region){
36927         this.region = region;
36928         this.setActiveClass(region && !this.background);
36929     },
36930     
36931     
36932     setActiveClass: function(state)
36933     {
36934         if(state){
36935            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36936            this.el.setStyle('position','relative');
36937         }else{
36938            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36939            this.el.setStyle('position', 'absolute');
36940         } 
36941     },
36942     
36943     /**
36944      * Returns the toolbar for this Panel if one was configured. 
36945      * @return {Roo.Toolbar} 
36946      */
36947     getToolbar : function(){
36948         return this.toolbar;
36949     },
36950     
36951     setActiveState : function(active)
36952     {
36953         this.active = active;
36954         this.setActiveClass(active);
36955         if(!active){
36956             if(this.fireEvent("deactivate", this) === false){
36957                 return false;
36958             }
36959             return true;
36960         }
36961         this.fireEvent("activate", this);
36962         return true;
36963     },
36964     /**
36965      * Updates this panel's element
36966      * @param {String} content The new content
36967      * @param {Boolean} loadScripts (optional) true to look for and process scripts
36968     */
36969     setContent : function(content, loadScripts){
36970         this.el.update(content, loadScripts);
36971     },
36972
36973     ignoreResize : function(w, h){
36974         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36975             return true;
36976         }else{
36977             this.lastSize = {width: w, height: h};
36978             return false;
36979         }
36980     },
36981     /**
36982      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36983      * @return {Roo.UpdateManager} The UpdateManager
36984      */
36985     getUpdateManager : function(){
36986         return this.el.getUpdateManager();
36987     },
36988      /**
36989      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36990      * @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:
36991 <pre><code>
36992 panel.load({
36993     url: "your-url.php",
36994     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36995     callback: yourFunction,
36996     scope: yourObject, //(optional scope)
36997     discardUrl: false,
36998     nocache: false,
36999     text: "Loading...",
37000     timeout: 30,
37001     scripts: false
37002 });
37003 </code></pre>
37004      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37005      * 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.
37006      * @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}
37007      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37008      * @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.
37009      * @return {Roo.ContentPanel} this
37010      */
37011     load : function(){
37012         var um = this.el.getUpdateManager();
37013         um.update.apply(um, arguments);
37014         return this;
37015     },
37016
37017
37018     /**
37019      * 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.
37020      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37021      * @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)
37022      * @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)
37023      * @return {Roo.UpdateManager} The UpdateManager
37024      */
37025     setUrl : function(url, params, loadOnce){
37026         if(this.refreshDelegate){
37027             this.removeListener("activate", this.refreshDelegate);
37028         }
37029         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37030         this.on("activate", this.refreshDelegate);
37031         return this.el.getUpdateManager();
37032     },
37033     
37034     _handleRefresh : function(url, params, loadOnce){
37035         if(!loadOnce || !this.loaded){
37036             var updater = this.el.getUpdateManager();
37037             updater.update(url, params, this._setLoaded.createDelegate(this));
37038         }
37039     },
37040     
37041     _setLoaded : function(){
37042         this.loaded = true;
37043     }, 
37044     
37045     /**
37046      * Returns this panel's id
37047      * @return {String} 
37048      */
37049     getId : function(){
37050         return this.el.id;
37051     },
37052     
37053     /** 
37054      * Returns this panel's element - used by regiosn to add.
37055      * @return {Roo.Element} 
37056      */
37057     getEl : function(){
37058         return this.wrapEl || this.el;
37059     },
37060     
37061    
37062     
37063     adjustForComponents : function(width, height)
37064     {
37065         //Roo.log('adjustForComponents ');
37066         if(this.resizeEl != this.el){
37067             width -= this.el.getFrameWidth('lr');
37068             height -= this.el.getFrameWidth('tb');
37069         }
37070         if(this.toolbar){
37071             var te = this.toolbar.getEl();
37072             te.setWidth(width);
37073             height -= te.getHeight();
37074         }
37075         if(this.footer){
37076             var te = this.footer.getEl();
37077             te.setWidth(width);
37078             height -= te.getHeight();
37079         }
37080         
37081         
37082         if(this.adjustments){
37083             width += this.adjustments[0];
37084             height += this.adjustments[1];
37085         }
37086         return {"width": width, "height": height};
37087     },
37088     
37089     setSize : function(width, height){
37090         if(this.fitToFrame && !this.ignoreResize(width, height)){
37091             if(this.fitContainer && this.resizeEl != this.el){
37092                 this.el.setSize(width, height);
37093             }
37094             var size = this.adjustForComponents(width, height);
37095             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37096             this.fireEvent('resize', this, size.width, size.height);
37097         }
37098     },
37099     
37100     /**
37101      * Returns this panel's title
37102      * @return {String} 
37103      */
37104     getTitle : function(){
37105         
37106         if (typeof(this.title) != 'object') {
37107             return this.title;
37108         }
37109         
37110         var t = '';
37111         for (var k in this.title) {
37112             if (!this.title.hasOwnProperty(k)) {
37113                 continue;
37114             }
37115             
37116             if (k.indexOf('-') >= 0) {
37117                 var s = k.split('-');
37118                 for (var i = 0; i<s.length; i++) {
37119                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37120                 }
37121             } else {
37122                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37123             }
37124         }
37125         return t;
37126     },
37127     
37128     /**
37129      * Set this panel's title
37130      * @param {String} title
37131      */
37132     setTitle : function(title){
37133         this.title = title;
37134         if(this.region){
37135             this.region.updatePanelTitle(this, title);
37136         }
37137     },
37138     
37139     /**
37140      * Returns true is this panel was configured to be closable
37141      * @return {Boolean} 
37142      */
37143     isClosable : function(){
37144         return this.closable;
37145     },
37146     
37147     beforeSlide : function(){
37148         this.el.clip();
37149         this.resizeEl.clip();
37150     },
37151     
37152     afterSlide : function(){
37153         this.el.unclip();
37154         this.resizeEl.unclip();
37155     },
37156     
37157     /**
37158      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
37159      *   Will fail silently if the {@link #setUrl} method has not been called.
37160      *   This does not activate the panel, just updates its content.
37161      */
37162     refresh : function(){
37163         if(this.refreshDelegate){
37164            this.loaded = false;
37165            this.refreshDelegate();
37166         }
37167     },
37168     
37169     /**
37170      * Destroys this panel
37171      */
37172     destroy : function(){
37173         this.el.removeAllListeners();
37174         var tempEl = document.createElement("span");
37175         tempEl.appendChild(this.el.dom);
37176         tempEl.innerHTML = "";
37177         this.el.remove();
37178         this.el = null;
37179     },
37180     
37181     /**
37182      * form - if the content panel contains a form - this is a reference to it.
37183      * @type {Roo.form.Form}
37184      */
37185     form : false,
37186     /**
37187      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37188      *    This contains a reference to it.
37189      * @type {Roo.View}
37190      */
37191     view : false,
37192     
37193       /**
37194      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37195      * <pre><code>
37196
37197 layout.addxtype({
37198        xtype : 'Form',
37199        items: [ .... ]
37200    }
37201 );
37202
37203 </code></pre>
37204      * @param {Object} cfg Xtype definition of item to add.
37205      */
37206     
37207     
37208     getChildContainer: function () {
37209         return this.getEl();
37210     }
37211     
37212     
37213     /*
37214         var  ret = new Roo.factory(cfg);
37215         return ret;
37216         
37217         
37218         // add form..
37219         if (cfg.xtype.match(/^Form$/)) {
37220             
37221             var el;
37222             //if (this.footer) {
37223             //    el = this.footer.container.insertSibling(false, 'before');
37224             //} else {
37225                 el = this.el.createChild();
37226             //}
37227
37228             this.form = new  Roo.form.Form(cfg);
37229             
37230             
37231             if ( this.form.allItems.length) {
37232                 this.form.render(el.dom);
37233             }
37234             return this.form;
37235         }
37236         // should only have one of theses..
37237         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37238             // views.. should not be just added - used named prop 'view''
37239             
37240             cfg.el = this.el.appendChild(document.createElement("div"));
37241             // factory?
37242             
37243             var ret = new Roo.factory(cfg);
37244              
37245              ret.render && ret.render(false, ''); // render blank..
37246             this.view = ret;
37247             return ret;
37248         }
37249         return false;
37250     }
37251     \*/
37252 });
37253  
37254 /**
37255  * @class Roo.bootstrap.panel.Grid
37256  * @extends Roo.bootstrap.panel.Content
37257  * @constructor
37258  * Create a new GridPanel.
37259  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37260  * @param {Object} config A the config object
37261   
37262  */
37263
37264
37265
37266 Roo.bootstrap.panel.Grid = function(config)
37267 {
37268     
37269       
37270     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37271         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37272
37273     config.el = this.wrapper;
37274     //this.el = this.wrapper;
37275     
37276       if (config.container) {
37277         // ctor'ed from a Border/panel.grid
37278         
37279         
37280         this.wrapper.setStyle("overflow", "hidden");
37281         this.wrapper.addClass('roo-grid-container');
37282
37283     }
37284     
37285     
37286     if(config.toolbar){
37287         var tool_el = this.wrapper.createChild();    
37288         this.toolbar = Roo.factory(config.toolbar);
37289         var ti = [];
37290         if (config.toolbar.items) {
37291             ti = config.toolbar.items ;
37292             delete config.toolbar.items ;
37293         }
37294         
37295         var nitems = [];
37296         this.toolbar.render(tool_el);
37297         for(var i =0;i < ti.length;i++) {
37298           //  Roo.log(['add child', items[i]]);
37299             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37300         }
37301         this.toolbar.items = nitems;
37302         
37303         delete config.toolbar;
37304     }
37305     
37306     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37307     config.grid.scrollBody = true;;
37308     config.grid.monitorWindowResize = false; // turn off autosizing
37309     config.grid.autoHeight = false;
37310     config.grid.autoWidth = false;
37311     
37312     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37313     
37314     if (config.background) {
37315         // render grid on panel activation (if panel background)
37316         this.on('activate', function(gp) {
37317             if (!gp.grid.rendered) {
37318                 gp.grid.render(this.wrapper);
37319                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37320             }
37321         });
37322             
37323     } else {
37324         this.grid.render(this.wrapper);
37325         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37326
37327     }
37328     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37329     // ??? needed ??? config.el = this.wrapper;
37330     
37331     
37332     
37333   
37334     // xtype created footer. - not sure if will work as we normally have to render first..
37335     if (this.footer && !this.footer.el && this.footer.xtype) {
37336         
37337         var ctr = this.grid.getView().getFooterPanel(true);
37338         this.footer.dataSource = this.grid.dataSource;
37339         this.footer = Roo.factory(this.footer, Roo);
37340         this.footer.render(ctr);
37341         
37342     }
37343     
37344     
37345     
37346     
37347      
37348 };
37349
37350 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37351     getId : function(){
37352         return this.grid.id;
37353     },
37354     
37355     /**
37356      * Returns the grid for this panel
37357      * @return {Roo.bootstrap.Table} 
37358      */
37359     getGrid : function(){
37360         return this.grid;    
37361     },
37362     
37363     setSize : function(width, height){
37364         if(!this.ignoreResize(width, height)){
37365             var grid = this.grid;
37366             var size = this.adjustForComponents(width, height);
37367             var gridel = grid.getGridEl();
37368             gridel.setSize(size.width, size.height);
37369             /*
37370             var thd = grid.getGridEl().select('thead',true).first();
37371             var tbd = grid.getGridEl().select('tbody', true).first();
37372             if (tbd) {
37373                 tbd.setSize(width, height - thd.getHeight());
37374             }
37375             */
37376             grid.autoSize();
37377         }
37378     },
37379      
37380     
37381     
37382     beforeSlide : function(){
37383         this.grid.getView().scroller.clip();
37384     },
37385     
37386     afterSlide : function(){
37387         this.grid.getView().scroller.unclip();
37388     },
37389     
37390     destroy : function(){
37391         this.grid.destroy();
37392         delete this.grid;
37393         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37394     }
37395 });
37396
37397 /**
37398  * @class Roo.bootstrap.panel.Nest
37399  * @extends Roo.bootstrap.panel.Content
37400  * @constructor
37401  * Create a new Panel, that can contain a layout.Border.
37402  * 
37403  * 
37404  * @param {Roo.BorderLayout} layout The layout for this panel
37405  * @param {String/Object} config A string to set only the title or a config object
37406  */
37407 Roo.bootstrap.panel.Nest = function(config)
37408 {
37409     // construct with only one argument..
37410     /* FIXME - implement nicer consturctors
37411     if (layout.layout) {
37412         config = layout;
37413         layout = config.layout;
37414         delete config.layout;
37415     }
37416     if (layout.xtype && !layout.getEl) {
37417         // then layout needs constructing..
37418         layout = Roo.factory(layout, Roo);
37419     }
37420     */
37421     
37422     config.el =  config.layout.getEl();
37423     
37424     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37425     
37426     config.layout.monitorWindowResize = false; // turn off autosizing
37427     this.layout = config.layout;
37428     this.layout.getEl().addClass("roo-layout-nested-layout");
37429     
37430     
37431     
37432     
37433 };
37434
37435 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37436
37437     setSize : function(width, height){
37438         if(!this.ignoreResize(width, height)){
37439             var size = this.adjustForComponents(width, height);
37440             var el = this.layout.getEl();
37441             if (size.height < 1) {
37442                 el.setWidth(size.width);   
37443             } else {
37444                 el.setSize(size.width, size.height);
37445             }
37446             var touch = el.dom.offsetWidth;
37447             this.layout.layout();
37448             // ie requires a double layout on the first pass
37449             if(Roo.isIE && !this.initialized){
37450                 this.initialized = true;
37451                 this.layout.layout();
37452             }
37453         }
37454     },
37455     
37456     // activate all subpanels if not currently active..
37457     
37458     setActiveState : function(active){
37459         this.active = active;
37460         this.setActiveClass(active);
37461         
37462         if(!active){
37463             this.fireEvent("deactivate", this);
37464             return;
37465         }
37466         
37467         this.fireEvent("activate", this);
37468         // not sure if this should happen before or after..
37469         if (!this.layout) {
37470             return; // should not happen..
37471         }
37472         var reg = false;
37473         for (var r in this.layout.regions) {
37474             reg = this.layout.getRegion(r);
37475             if (reg.getActivePanel()) {
37476                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37477                 reg.setActivePanel(reg.getActivePanel());
37478                 continue;
37479             }
37480             if (!reg.panels.length) {
37481                 continue;
37482             }
37483             reg.showPanel(reg.getPanel(0));
37484         }
37485         
37486         
37487         
37488         
37489     },
37490     
37491     /**
37492      * Returns the nested BorderLayout for this panel
37493      * @return {Roo.BorderLayout} 
37494      */
37495     getLayout : function(){
37496         return this.layout;
37497     },
37498     
37499      /**
37500      * Adds a xtype elements to the layout of the nested panel
37501      * <pre><code>
37502
37503 panel.addxtype({
37504        xtype : 'ContentPanel',
37505        region: 'west',
37506        items: [ .... ]
37507    }
37508 );
37509
37510 panel.addxtype({
37511         xtype : 'NestedLayoutPanel',
37512         region: 'west',
37513         layout: {
37514            center: { },
37515            west: { }   
37516         },
37517         items : [ ... list of content panels or nested layout panels.. ]
37518    }
37519 );
37520 </code></pre>
37521      * @param {Object} cfg Xtype definition of item to add.
37522      */
37523     addxtype : function(cfg) {
37524         return this.layout.addxtype(cfg);
37525     
37526     }
37527 });        /*
37528  * Based on:
37529  * Ext JS Library 1.1.1
37530  * Copyright(c) 2006-2007, Ext JS, LLC.
37531  *
37532  * Originally Released Under LGPL - original licence link has changed is not relivant.
37533  *
37534  * Fork - LGPL
37535  * <script type="text/javascript">
37536  */
37537 /**
37538  * @class Roo.TabPanel
37539  * @extends Roo.util.Observable
37540  * A lightweight tab container.
37541  * <br><br>
37542  * Usage:
37543  * <pre><code>
37544 // basic tabs 1, built from existing content
37545 var tabs = new Roo.TabPanel("tabs1");
37546 tabs.addTab("script", "View Script");
37547 tabs.addTab("markup", "View Markup");
37548 tabs.activate("script");
37549
37550 // more advanced tabs, built from javascript
37551 var jtabs = new Roo.TabPanel("jtabs");
37552 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37553
37554 // set up the UpdateManager
37555 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37556 var updater = tab2.getUpdateManager();
37557 updater.setDefaultUrl("ajax1.htm");
37558 tab2.on('activate', updater.refresh, updater, true);
37559
37560 // Use setUrl for Ajax loading
37561 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37562 tab3.setUrl("ajax2.htm", null, true);
37563
37564 // Disabled tab
37565 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37566 tab4.disable();
37567
37568 jtabs.activate("jtabs-1");
37569  * </code></pre>
37570  * @constructor
37571  * Create a new TabPanel.
37572  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37573  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37574  */
37575 Roo.bootstrap.panel.Tabs = function(config){
37576     /**
37577     * The container element for this TabPanel.
37578     * @type Roo.Element
37579     */
37580     this.el = Roo.get(config.el);
37581     delete config.el;
37582     if(config){
37583         if(typeof config == "boolean"){
37584             this.tabPosition = config ? "bottom" : "top";
37585         }else{
37586             Roo.apply(this, config);
37587         }
37588     }
37589     
37590     if(this.tabPosition == "bottom"){
37591         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37592         this.el.addClass("roo-tabs-bottom");
37593     }
37594     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37595     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37596     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37597     if(Roo.isIE){
37598         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37599     }
37600     if(this.tabPosition != "bottom"){
37601         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37602          * @type Roo.Element
37603          */
37604         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37605         this.el.addClass("roo-tabs-top");
37606     }
37607     this.items = [];
37608
37609     this.bodyEl.setStyle("position", "relative");
37610
37611     this.active = null;
37612     this.activateDelegate = this.activate.createDelegate(this);
37613
37614     this.addEvents({
37615         /**
37616          * @event tabchange
37617          * Fires when the active tab changes
37618          * @param {Roo.TabPanel} this
37619          * @param {Roo.TabPanelItem} activePanel The new active tab
37620          */
37621         "tabchange": true,
37622         /**
37623          * @event beforetabchange
37624          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37625          * @param {Roo.TabPanel} this
37626          * @param {Object} e Set cancel to true on this object to cancel the tab change
37627          * @param {Roo.TabPanelItem} tab The tab being changed to
37628          */
37629         "beforetabchange" : true
37630     });
37631
37632     Roo.EventManager.onWindowResize(this.onResize, this);
37633     this.cpad = this.el.getPadding("lr");
37634     this.hiddenCount = 0;
37635
37636
37637     // toolbar on the tabbar support...
37638     if (this.toolbar) {
37639         alert("no toolbar support yet");
37640         this.toolbar  = false;
37641         /*
37642         var tcfg = this.toolbar;
37643         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37644         this.toolbar = new Roo.Toolbar(tcfg);
37645         if (Roo.isSafari) {
37646             var tbl = tcfg.container.child('table', true);
37647             tbl.setAttribute('width', '100%');
37648         }
37649         */
37650         
37651     }
37652    
37653
37654
37655     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37656 };
37657
37658 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37659     /*
37660      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37661      */
37662     tabPosition : "top",
37663     /*
37664      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37665      */
37666     currentTabWidth : 0,
37667     /*
37668      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37669      */
37670     minTabWidth : 40,
37671     /*
37672      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37673      */
37674     maxTabWidth : 250,
37675     /*
37676      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37677      */
37678     preferredTabWidth : 175,
37679     /*
37680      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37681      */
37682     resizeTabs : false,
37683     /*
37684      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37685      */
37686     monitorResize : true,
37687     /*
37688      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37689      */
37690     toolbar : false,
37691
37692     /**
37693      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37694      * @param {String} id The id of the div to use <b>or create</b>
37695      * @param {String} text The text for the tab
37696      * @param {String} content (optional) Content to put in the TabPanelItem body
37697      * @param {Boolean} closable (optional) True to create a close icon on the tab
37698      * @return {Roo.TabPanelItem} The created TabPanelItem
37699      */
37700     addTab : function(id, text, content, closable, tpl)
37701     {
37702         var item = new Roo.bootstrap.panel.TabItem({
37703             panel: this,
37704             id : id,
37705             text : text,
37706             closable : closable,
37707             tpl : tpl
37708         });
37709         this.addTabItem(item);
37710         if(content){
37711             item.setContent(content);
37712         }
37713         return item;
37714     },
37715
37716     /**
37717      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37718      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37719      * @return {Roo.TabPanelItem}
37720      */
37721     getTab : function(id){
37722         return this.items[id];
37723     },
37724
37725     /**
37726      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37727      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37728      */
37729     hideTab : function(id){
37730         var t = this.items[id];
37731         if(!t.isHidden()){
37732            t.setHidden(true);
37733            this.hiddenCount++;
37734            this.autoSizeTabs();
37735         }
37736     },
37737
37738     /**
37739      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37740      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37741      */
37742     unhideTab : function(id){
37743         var t = this.items[id];
37744         if(t.isHidden()){
37745            t.setHidden(false);
37746            this.hiddenCount--;
37747            this.autoSizeTabs();
37748         }
37749     },
37750
37751     /**
37752      * Adds an existing {@link Roo.TabPanelItem}.
37753      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37754      */
37755     addTabItem : function(item){
37756         this.items[item.id] = item;
37757         this.items.push(item);
37758       //  if(this.resizeTabs){
37759     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37760   //         this.autoSizeTabs();
37761 //        }else{
37762 //            item.autoSize();
37763        // }
37764     },
37765
37766     /**
37767      * Removes a {@link Roo.TabPanelItem}.
37768      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37769      */
37770     removeTab : function(id){
37771         var items = this.items;
37772         var tab = items[id];
37773         if(!tab) { return; }
37774         var index = items.indexOf(tab);
37775         if(this.active == tab && items.length > 1){
37776             var newTab = this.getNextAvailable(index);
37777             if(newTab) {
37778                 newTab.activate();
37779             }
37780         }
37781         this.stripEl.dom.removeChild(tab.pnode.dom);
37782         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37783             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37784         }
37785         items.splice(index, 1);
37786         delete this.items[tab.id];
37787         tab.fireEvent("close", tab);
37788         tab.purgeListeners();
37789         this.autoSizeTabs();
37790     },
37791
37792     getNextAvailable : function(start){
37793         var items = this.items;
37794         var index = start;
37795         // look for a next tab that will slide over to
37796         // replace the one being removed
37797         while(index < items.length){
37798             var item = items[++index];
37799             if(item && !item.isHidden()){
37800                 return item;
37801             }
37802         }
37803         // if one isn't found select the previous tab (on the left)
37804         index = start;
37805         while(index >= 0){
37806             var item = items[--index];
37807             if(item && !item.isHidden()){
37808                 return item;
37809             }
37810         }
37811         return null;
37812     },
37813
37814     /**
37815      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37816      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37817      */
37818     disableTab : function(id){
37819         var tab = this.items[id];
37820         if(tab && this.active != tab){
37821             tab.disable();
37822         }
37823     },
37824
37825     /**
37826      * Enables a {@link Roo.TabPanelItem} that is disabled.
37827      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37828      */
37829     enableTab : function(id){
37830         var tab = this.items[id];
37831         tab.enable();
37832     },
37833
37834     /**
37835      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37836      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37837      * @return {Roo.TabPanelItem} The TabPanelItem.
37838      */
37839     activate : function(id){
37840         var tab = this.items[id];
37841         if(!tab){
37842             return null;
37843         }
37844         if(tab == this.active || tab.disabled){
37845             return tab;
37846         }
37847         var e = {};
37848         this.fireEvent("beforetabchange", this, e, tab);
37849         if(e.cancel !== true && !tab.disabled){
37850             if(this.active){
37851                 this.active.hide();
37852             }
37853             this.active = this.items[id];
37854             this.active.show();
37855             this.fireEvent("tabchange", this, this.active);
37856         }
37857         return tab;
37858     },
37859
37860     /**
37861      * Gets the active {@link Roo.TabPanelItem}.
37862      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37863      */
37864     getActiveTab : function(){
37865         return this.active;
37866     },
37867
37868     /**
37869      * Updates the tab body element to fit the height of the container element
37870      * for overflow scrolling
37871      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37872      */
37873     syncHeight : function(targetHeight){
37874         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37875         var bm = this.bodyEl.getMargins();
37876         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37877         this.bodyEl.setHeight(newHeight);
37878         return newHeight;
37879     },
37880
37881     onResize : function(){
37882         if(this.monitorResize){
37883             this.autoSizeTabs();
37884         }
37885     },
37886
37887     /**
37888      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37889      */
37890     beginUpdate : function(){
37891         this.updating = true;
37892     },
37893
37894     /**
37895      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37896      */
37897     endUpdate : function(){
37898         this.updating = false;
37899         this.autoSizeTabs();
37900     },
37901
37902     /**
37903      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37904      */
37905     autoSizeTabs : function(){
37906         var count = this.items.length;
37907         var vcount = count - this.hiddenCount;
37908         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37909             return;
37910         }
37911         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37912         var availWidth = Math.floor(w / vcount);
37913         var b = this.stripBody;
37914         if(b.getWidth() > w){
37915             var tabs = this.items;
37916             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37917             if(availWidth < this.minTabWidth){
37918                 /*if(!this.sleft){    // incomplete scrolling code
37919                     this.createScrollButtons();
37920                 }
37921                 this.showScroll();
37922                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37923             }
37924         }else{
37925             if(this.currentTabWidth < this.preferredTabWidth){
37926                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37927             }
37928         }
37929     },
37930
37931     /**
37932      * Returns the number of tabs in this TabPanel.
37933      * @return {Number}
37934      */
37935      getCount : function(){
37936          return this.items.length;
37937      },
37938
37939     /**
37940      * Resizes all the tabs to the passed width
37941      * @param {Number} The new width
37942      */
37943     setTabWidth : function(width){
37944         this.currentTabWidth = width;
37945         for(var i = 0, len = this.items.length; i < len; i++) {
37946                 if(!this.items[i].isHidden()) {
37947                 this.items[i].setWidth(width);
37948             }
37949         }
37950     },
37951
37952     /**
37953      * Destroys this TabPanel
37954      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37955      */
37956     destroy : function(removeEl){
37957         Roo.EventManager.removeResizeListener(this.onResize, this);
37958         for(var i = 0, len = this.items.length; i < len; i++){
37959             this.items[i].purgeListeners();
37960         }
37961         if(removeEl === true){
37962             this.el.update("");
37963             this.el.remove();
37964         }
37965     },
37966     
37967     createStrip : function(container)
37968     {
37969         var strip = document.createElement("nav");
37970         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37971         container.appendChild(strip);
37972         return strip;
37973     },
37974     
37975     createStripList : function(strip)
37976     {
37977         // div wrapper for retard IE
37978         // returns the "tr" element.
37979         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37980         //'<div class="x-tabs-strip-wrap">'+
37981           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37982           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37983         return strip.firstChild; //.firstChild.firstChild.firstChild;
37984     },
37985     createBody : function(container)
37986     {
37987         var body = document.createElement("div");
37988         Roo.id(body, "tab-body");
37989         //Roo.fly(body).addClass("x-tabs-body");
37990         Roo.fly(body).addClass("tab-content");
37991         container.appendChild(body);
37992         return body;
37993     },
37994     createItemBody :function(bodyEl, id){
37995         var body = Roo.getDom(id);
37996         if(!body){
37997             body = document.createElement("div");
37998             body.id = id;
37999         }
38000         //Roo.fly(body).addClass("x-tabs-item-body");
38001         Roo.fly(body).addClass("tab-pane");
38002          bodyEl.insertBefore(body, bodyEl.firstChild);
38003         return body;
38004     },
38005     /** @private */
38006     createStripElements :  function(stripEl, text, closable, tpl)
38007     {
38008         var td = document.createElement("li"); // was td..
38009         
38010         
38011         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38012         
38013         
38014         stripEl.appendChild(td);
38015         /*if(closable){
38016             td.className = "x-tabs-closable";
38017             if(!this.closeTpl){
38018                 this.closeTpl = new Roo.Template(
38019                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38020                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38021                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
38022                 );
38023             }
38024             var el = this.closeTpl.overwrite(td, {"text": text});
38025             var close = el.getElementsByTagName("div")[0];
38026             var inner = el.getElementsByTagName("em")[0];
38027             return {"el": el, "close": close, "inner": inner};
38028         } else {
38029         */
38030         // not sure what this is..
38031 //            if(!this.tabTpl){
38032                 //this.tabTpl = new Roo.Template(
38033                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38034                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38035                 //);
38036 //                this.tabTpl = new Roo.Template(
38037 //                   '<a href="#">' +
38038 //                   '<span unselectable="on"' +
38039 //                            (this.disableTooltips ? '' : ' title="{text}"') +
38040 //                            ' >{text}</span></a>'
38041 //                );
38042 //                
38043 //            }
38044
38045
38046             var template = tpl || this.tabTpl || false;
38047             
38048             if(!template){
38049                 
38050                 template = new Roo.Template(
38051                    '<a href="#">' +
38052                    '<span unselectable="on"' +
38053                             (this.disableTooltips ? '' : ' title="{text}"') +
38054                             ' >{text}</span></a>'
38055                 );
38056             }
38057             
38058             switch (typeof(template)) {
38059                 case 'object' :
38060                     break;
38061                 case 'string' :
38062                     template = new Roo.Template(template);
38063                     break;
38064                 default :
38065                     break;
38066             }
38067             
38068             var el = template.overwrite(td, {"text": text});
38069             
38070             var inner = el.getElementsByTagName("span")[0];
38071             
38072             return {"el": el, "inner": inner};
38073             
38074     }
38075         
38076     
38077 });
38078
38079 /**
38080  * @class Roo.TabPanelItem
38081  * @extends Roo.util.Observable
38082  * Represents an individual item (tab plus body) in a TabPanel.
38083  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38084  * @param {String} id The id of this TabPanelItem
38085  * @param {String} text The text for the tab of this TabPanelItem
38086  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38087  */
38088 Roo.bootstrap.panel.TabItem = function(config){
38089     /**
38090      * The {@link Roo.TabPanel} this TabPanelItem belongs to
38091      * @type Roo.TabPanel
38092      */
38093     this.tabPanel = config.panel;
38094     /**
38095      * The id for this TabPanelItem
38096      * @type String
38097      */
38098     this.id = config.id;
38099     /** @private */
38100     this.disabled = false;
38101     /** @private */
38102     this.text = config.text;
38103     /** @private */
38104     this.loaded = false;
38105     this.closable = config.closable;
38106
38107     /**
38108      * The body element for this TabPanelItem.
38109      * @type Roo.Element
38110      */
38111     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38112     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38113     this.bodyEl.setStyle("display", "block");
38114     this.bodyEl.setStyle("zoom", "1");
38115     //this.hideAction();
38116
38117     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38118     /** @private */
38119     this.el = Roo.get(els.el);
38120     this.inner = Roo.get(els.inner, true);
38121     this.textEl = Roo.get(this.el.dom.firstChild, true);
38122     this.pnode = Roo.get(els.el.parentNode, true);
38123 //    this.el.on("mousedown", this.onTabMouseDown, this);
38124     this.el.on("click", this.onTabClick, this);
38125     /** @private */
38126     if(config.closable){
38127         var c = Roo.get(els.close, true);
38128         c.dom.title = this.closeText;
38129         c.addClassOnOver("close-over");
38130         c.on("click", this.closeClick, this);
38131      }
38132
38133     this.addEvents({
38134          /**
38135          * @event activate
38136          * Fires when this tab becomes the active tab.
38137          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38138          * @param {Roo.TabPanelItem} this
38139          */
38140         "activate": true,
38141         /**
38142          * @event beforeclose
38143          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38144          * @param {Roo.TabPanelItem} this
38145          * @param {Object} e Set cancel to true on this object to cancel the close.
38146          */
38147         "beforeclose": true,
38148         /**
38149          * @event close
38150          * Fires when this tab is closed.
38151          * @param {Roo.TabPanelItem} this
38152          */
38153          "close": true,
38154         /**
38155          * @event deactivate
38156          * Fires when this tab is no longer the active tab.
38157          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38158          * @param {Roo.TabPanelItem} this
38159          */
38160          "deactivate" : true
38161     });
38162     this.hidden = false;
38163
38164     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38165 };
38166
38167 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38168            {
38169     purgeListeners : function(){
38170        Roo.util.Observable.prototype.purgeListeners.call(this);
38171        this.el.removeAllListeners();
38172     },
38173     /**
38174      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38175      */
38176     show : function(){
38177         this.pnode.addClass("active");
38178         this.showAction();
38179         if(Roo.isOpera){
38180             this.tabPanel.stripWrap.repaint();
38181         }
38182         this.fireEvent("activate", this.tabPanel, this);
38183     },
38184
38185     /**
38186      * Returns true if this tab is the active tab.
38187      * @return {Boolean}
38188      */
38189     isActive : function(){
38190         return this.tabPanel.getActiveTab() == this;
38191     },
38192
38193     /**
38194      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38195      */
38196     hide : function(){
38197         this.pnode.removeClass("active");
38198         this.hideAction();
38199         this.fireEvent("deactivate", this.tabPanel, this);
38200     },
38201
38202     hideAction : function(){
38203         this.bodyEl.hide();
38204         this.bodyEl.setStyle("position", "absolute");
38205         this.bodyEl.setLeft("-20000px");
38206         this.bodyEl.setTop("-20000px");
38207     },
38208
38209     showAction : function(){
38210         this.bodyEl.setStyle("position", "relative");
38211         this.bodyEl.setTop("");
38212         this.bodyEl.setLeft("");
38213         this.bodyEl.show();
38214     },
38215
38216     /**
38217      * Set the tooltip for the tab.
38218      * @param {String} tooltip The tab's tooltip
38219      */
38220     setTooltip : function(text){
38221         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38222             this.textEl.dom.qtip = text;
38223             this.textEl.dom.removeAttribute('title');
38224         }else{
38225             this.textEl.dom.title = text;
38226         }
38227     },
38228
38229     onTabClick : function(e){
38230         e.preventDefault();
38231         this.tabPanel.activate(this.id);
38232     },
38233
38234     onTabMouseDown : function(e){
38235         e.preventDefault();
38236         this.tabPanel.activate(this.id);
38237     },
38238 /*
38239     getWidth : function(){
38240         return this.inner.getWidth();
38241     },
38242
38243     setWidth : function(width){
38244         var iwidth = width - this.pnode.getPadding("lr");
38245         this.inner.setWidth(iwidth);
38246         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38247         this.pnode.setWidth(width);
38248     },
38249 */
38250     /**
38251      * Show or hide the tab
38252      * @param {Boolean} hidden True to hide or false to show.
38253      */
38254     setHidden : function(hidden){
38255         this.hidden = hidden;
38256         this.pnode.setStyle("display", hidden ? "none" : "");
38257     },
38258
38259     /**
38260      * Returns true if this tab is "hidden"
38261      * @return {Boolean}
38262      */
38263     isHidden : function(){
38264         return this.hidden;
38265     },
38266
38267     /**
38268      * Returns the text for this tab
38269      * @return {String}
38270      */
38271     getText : function(){
38272         return this.text;
38273     },
38274     /*
38275     autoSize : function(){
38276         //this.el.beginMeasure();
38277         this.textEl.setWidth(1);
38278         /*
38279          *  #2804 [new] Tabs in Roojs
38280          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38281          */
38282         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38283         //this.el.endMeasure();
38284     //},
38285
38286     /**
38287      * Sets the text for the tab (Note: this also sets the tooltip text)
38288      * @param {String} text The tab's text and tooltip
38289      */
38290     setText : function(text){
38291         this.text = text;
38292         this.textEl.update(text);
38293         this.setTooltip(text);
38294         //if(!this.tabPanel.resizeTabs){
38295         //    this.autoSize();
38296         //}
38297     },
38298     /**
38299      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38300      */
38301     activate : function(){
38302         this.tabPanel.activate(this.id);
38303     },
38304
38305     /**
38306      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38307      */
38308     disable : function(){
38309         if(this.tabPanel.active != this){
38310             this.disabled = true;
38311             this.pnode.addClass("disabled");
38312         }
38313     },
38314
38315     /**
38316      * Enables this TabPanelItem if it was previously disabled.
38317      */
38318     enable : function(){
38319         this.disabled = false;
38320         this.pnode.removeClass("disabled");
38321     },
38322
38323     /**
38324      * Sets the content for this TabPanelItem.
38325      * @param {String} content The content
38326      * @param {Boolean} loadScripts true to look for and load scripts
38327      */
38328     setContent : function(content, loadScripts){
38329         this.bodyEl.update(content, loadScripts);
38330     },
38331
38332     /**
38333      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38334      * @return {Roo.UpdateManager} The UpdateManager
38335      */
38336     getUpdateManager : function(){
38337         return this.bodyEl.getUpdateManager();
38338     },
38339
38340     /**
38341      * Set a URL to be used to load the content for this TabPanelItem.
38342      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38343      * @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)
38344      * @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)
38345      * @return {Roo.UpdateManager} The UpdateManager
38346      */
38347     setUrl : function(url, params, loadOnce){
38348         if(this.refreshDelegate){
38349             this.un('activate', this.refreshDelegate);
38350         }
38351         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38352         this.on("activate", this.refreshDelegate);
38353         return this.bodyEl.getUpdateManager();
38354     },
38355
38356     /** @private */
38357     _handleRefresh : function(url, params, loadOnce){
38358         if(!loadOnce || !this.loaded){
38359             var updater = this.bodyEl.getUpdateManager();
38360             updater.update(url, params, this._setLoaded.createDelegate(this));
38361         }
38362     },
38363
38364     /**
38365      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38366      *   Will fail silently if the setUrl method has not been called.
38367      *   This does not activate the panel, just updates its content.
38368      */
38369     refresh : function(){
38370         if(this.refreshDelegate){
38371            this.loaded = false;
38372            this.refreshDelegate();
38373         }
38374     },
38375
38376     /** @private */
38377     _setLoaded : function(){
38378         this.loaded = true;
38379     },
38380
38381     /** @private */
38382     closeClick : function(e){
38383         var o = {};
38384         e.stopEvent();
38385         this.fireEvent("beforeclose", this, o);
38386         if(o.cancel !== true){
38387             this.tabPanel.removeTab(this.id);
38388         }
38389     },
38390     /**
38391      * The text displayed in the tooltip for the close icon.
38392      * @type String
38393      */
38394     closeText : "Close this tab"
38395 });
38396 /**
38397 *    This script refer to:
38398 *    Title: International Telephone Input
38399 *    Author: Jack O'Connor
38400 *    Code version:  v12.1.12
38401 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38402 **/
38403
38404 Roo.bootstrap.PhoneInputData = function() {
38405     var d = [
38406       [
38407         "Afghanistan (‫افغانستان‬‎)",
38408         "af",
38409         "93"
38410       ],
38411       [
38412         "Albania (Shqipëri)",
38413         "al",
38414         "355"
38415       ],
38416       [
38417         "Algeria (‫الجزائر‬‎)",
38418         "dz",
38419         "213"
38420       ],
38421       [
38422         "American Samoa",
38423         "as",
38424         "1684"
38425       ],
38426       [
38427         "Andorra",
38428         "ad",
38429         "376"
38430       ],
38431       [
38432         "Angola",
38433         "ao",
38434         "244"
38435       ],
38436       [
38437         "Anguilla",
38438         "ai",
38439         "1264"
38440       ],
38441       [
38442         "Antigua and Barbuda",
38443         "ag",
38444         "1268"
38445       ],
38446       [
38447         "Argentina",
38448         "ar",
38449         "54"
38450       ],
38451       [
38452         "Armenia (Հայաստան)",
38453         "am",
38454         "374"
38455       ],
38456       [
38457         "Aruba",
38458         "aw",
38459         "297"
38460       ],
38461       [
38462         "Australia",
38463         "au",
38464         "61",
38465         0
38466       ],
38467       [
38468         "Austria (Österreich)",
38469         "at",
38470         "43"
38471       ],
38472       [
38473         "Azerbaijan (Azərbaycan)",
38474         "az",
38475         "994"
38476       ],
38477       [
38478         "Bahamas",
38479         "bs",
38480         "1242"
38481       ],
38482       [
38483         "Bahrain (‫البحرين‬‎)",
38484         "bh",
38485         "973"
38486       ],
38487       [
38488         "Bangladesh (বাংলাদেশ)",
38489         "bd",
38490         "880"
38491       ],
38492       [
38493         "Barbados",
38494         "bb",
38495         "1246"
38496       ],
38497       [
38498         "Belarus (Беларусь)",
38499         "by",
38500         "375"
38501       ],
38502       [
38503         "Belgium (België)",
38504         "be",
38505         "32"
38506       ],
38507       [
38508         "Belize",
38509         "bz",
38510         "501"
38511       ],
38512       [
38513         "Benin (Bénin)",
38514         "bj",
38515         "229"
38516       ],
38517       [
38518         "Bermuda",
38519         "bm",
38520         "1441"
38521       ],
38522       [
38523         "Bhutan (འབྲུག)",
38524         "bt",
38525         "975"
38526       ],
38527       [
38528         "Bolivia",
38529         "bo",
38530         "591"
38531       ],
38532       [
38533         "Bosnia and Herzegovina (Босна и Херцеговина)",
38534         "ba",
38535         "387"
38536       ],
38537       [
38538         "Botswana",
38539         "bw",
38540         "267"
38541       ],
38542       [
38543         "Brazil (Brasil)",
38544         "br",
38545         "55"
38546       ],
38547       [
38548         "British Indian Ocean Territory",
38549         "io",
38550         "246"
38551       ],
38552       [
38553         "British Virgin Islands",
38554         "vg",
38555         "1284"
38556       ],
38557       [
38558         "Brunei",
38559         "bn",
38560         "673"
38561       ],
38562       [
38563         "Bulgaria (България)",
38564         "bg",
38565         "359"
38566       ],
38567       [
38568         "Burkina Faso",
38569         "bf",
38570         "226"
38571       ],
38572       [
38573         "Burundi (Uburundi)",
38574         "bi",
38575         "257"
38576       ],
38577       [
38578         "Cambodia (កម្ពុជា)",
38579         "kh",
38580         "855"
38581       ],
38582       [
38583         "Cameroon (Cameroun)",
38584         "cm",
38585         "237"
38586       ],
38587       [
38588         "Canada",
38589         "ca",
38590         "1",
38591         1,
38592         ["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"]
38593       ],
38594       [
38595         "Cape Verde (Kabu Verdi)",
38596         "cv",
38597         "238"
38598       ],
38599       [
38600         "Caribbean Netherlands",
38601         "bq",
38602         "599",
38603         1
38604       ],
38605       [
38606         "Cayman Islands",
38607         "ky",
38608         "1345"
38609       ],
38610       [
38611         "Central African Republic (République centrafricaine)",
38612         "cf",
38613         "236"
38614       ],
38615       [
38616         "Chad (Tchad)",
38617         "td",
38618         "235"
38619       ],
38620       [
38621         "Chile",
38622         "cl",
38623         "56"
38624       ],
38625       [
38626         "China (中国)",
38627         "cn",
38628         "86"
38629       ],
38630       [
38631         "Christmas Island",
38632         "cx",
38633         "61",
38634         2
38635       ],
38636       [
38637         "Cocos (Keeling) Islands",
38638         "cc",
38639         "61",
38640         1
38641       ],
38642       [
38643         "Colombia",
38644         "co",
38645         "57"
38646       ],
38647       [
38648         "Comoros (‫جزر القمر‬‎)",
38649         "km",
38650         "269"
38651       ],
38652       [
38653         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38654         "cd",
38655         "243"
38656       ],
38657       [
38658         "Congo (Republic) (Congo-Brazzaville)",
38659         "cg",
38660         "242"
38661       ],
38662       [
38663         "Cook Islands",
38664         "ck",
38665         "682"
38666       ],
38667       [
38668         "Costa Rica",
38669         "cr",
38670         "506"
38671       ],
38672       [
38673         "Côte d’Ivoire",
38674         "ci",
38675         "225"
38676       ],
38677       [
38678         "Croatia (Hrvatska)",
38679         "hr",
38680         "385"
38681       ],
38682       [
38683         "Cuba",
38684         "cu",
38685         "53"
38686       ],
38687       [
38688         "Curaçao",
38689         "cw",
38690         "599",
38691         0
38692       ],
38693       [
38694         "Cyprus (Κύπρος)",
38695         "cy",
38696         "357"
38697       ],
38698       [
38699         "Czech Republic (Česká republika)",
38700         "cz",
38701         "420"
38702       ],
38703       [
38704         "Denmark (Danmark)",
38705         "dk",
38706         "45"
38707       ],
38708       [
38709         "Djibouti",
38710         "dj",
38711         "253"
38712       ],
38713       [
38714         "Dominica",
38715         "dm",
38716         "1767"
38717       ],
38718       [
38719         "Dominican Republic (República Dominicana)",
38720         "do",
38721         "1",
38722         2,
38723         ["809", "829", "849"]
38724       ],
38725       [
38726         "Ecuador",
38727         "ec",
38728         "593"
38729       ],
38730       [
38731         "Egypt (‫مصر‬‎)",
38732         "eg",
38733         "20"
38734       ],
38735       [
38736         "El Salvador",
38737         "sv",
38738         "503"
38739       ],
38740       [
38741         "Equatorial Guinea (Guinea Ecuatorial)",
38742         "gq",
38743         "240"
38744       ],
38745       [
38746         "Eritrea",
38747         "er",
38748         "291"
38749       ],
38750       [
38751         "Estonia (Eesti)",
38752         "ee",
38753         "372"
38754       ],
38755       [
38756         "Ethiopia",
38757         "et",
38758         "251"
38759       ],
38760       [
38761         "Falkland Islands (Islas Malvinas)",
38762         "fk",
38763         "500"
38764       ],
38765       [
38766         "Faroe Islands (Føroyar)",
38767         "fo",
38768         "298"
38769       ],
38770       [
38771         "Fiji",
38772         "fj",
38773         "679"
38774       ],
38775       [
38776         "Finland (Suomi)",
38777         "fi",
38778         "358",
38779         0
38780       ],
38781       [
38782         "France",
38783         "fr",
38784         "33"
38785       ],
38786       [
38787         "French Guiana (Guyane française)",
38788         "gf",
38789         "594"
38790       ],
38791       [
38792         "French Polynesia (Polynésie française)",
38793         "pf",
38794         "689"
38795       ],
38796       [
38797         "Gabon",
38798         "ga",
38799         "241"
38800       ],
38801       [
38802         "Gambia",
38803         "gm",
38804         "220"
38805       ],
38806       [
38807         "Georgia (საქართველო)",
38808         "ge",
38809         "995"
38810       ],
38811       [
38812         "Germany (Deutschland)",
38813         "de",
38814         "49"
38815       ],
38816       [
38817         "Ghana (Gaana)",
38818         "gh",
38819         "233"
38820       ],
38821       [
38822         "Gibraltar",
38823         "gi",
38824         "350"
38825       ],
38826       [
38827         "Greece (Ελλάδα)",
38828         "gr",
38829         "30"
38830       ],
38831       [
38832         "Greenland (Kalaallit Nunaat)",
38833         "gl",
38834         "299"
38835       ],
38836       [
38837         "Grenada",
38838         "gd",
38839         "1473"
38840       ],
38841       [
38842         "Guadeloupe",
38843         "gp",
38844         "590",
38845         0
38846       ],
38847       [
38848         "Guam",
38849         "gu",
38850         "1671"
38851       ],
38852       [
38853         "Guatemala",
38854         "gt",
38855         "502"
38856       ],
38857       [
38858         "Guernsey",
38859         "gg",
38860         "44",
38861         1
38862       ],
38863       [
38864         "Guinea (Guinée)",
38865         "gn",
38866         "224"
38867       ],
38868       [
38869         "Guinea-Bissau (Guiné Bissau)",
38870         "gw",
38871         "245"
38872       ],
38873       [
38874         "Guyana",
38875         "gy",
38876         "592"
38877       ],
38878       [
38879         "Haiti",
38880         "ht",
38881         "509"
38882       ],
38883       [
38884         "Honduras",
38885         "hn",
38886         "504"
38887       ],
38888       [
38889         "Hong Kong (香港)",
38890         "hk",
38891         "852"
38892       ],
38893       [
38894         "Hungary (Magyarország)",
38895         "hu",
38896         "36"
38897       ],
38898       [
38899         "Iceland (Ísland)",
38900         "is",
38901         "354"
38902       ],
38903       [
38904         "India (भारत)",
38905         "in",
38906         "91"
38907       ],
38908       [
38909         "Indonesia",
38910         "id",
38911         "62"
38912       ],
38913       [
38914         "Iran (‫ایران‬‎)",
38915         "ir",
38916         "98"
38917       ],
38918       [
38919         "Iraq (‫العراق‬‎)",
38920         "iq",
38921         "964"
38922       ],
38923       [
38924         "Ireland",
38925         "ie",
38926         "353"
38927       ],
38928       [
38929         "Isle of Man",
38930         "im",
38931         "44",
38932         2
38933       ],
38934       [
38935         "Israel (‫ישראל‬‎)",
38936         "il",
38937         "972"
38938       ],
38939       [
38940         "Italy (Italia)",
38941         "it",
38942         "39",
38943         0
38944       ],
38945       [
38946         "Jamaica",
38947         "jm",
38948         "1876"
38949       ],
38950       [
38951         "Japan (日本)",
38952         "jp",
38953         "81"
38954       ],
38955       [
38956         "Jersey",
38957         "je",
38958         "44",
38959         3
38960       ],
38961       [
38962         "Jordan (‫الأردن‬‎)",
38963         "jo",
38964         "962"
38965       ],
38966       [
38967         "Kazakhstan (Казахстан)",
38968         "kz",
38969         "7",
38970         1
38971       ],
38972       [
38973         "Kenya",
38974         "ke",
38975         "254"
38976       ],
38977       [
38978         "Kiribati",
38979         "ki",
38980         "686"
38981       ],
38982       [
38983         "Kosovo",
38984         "xk",
38985         "383"
38986       ],
38987       [
38988         "Kuwait (‫الكويت‬‎)",
38989         "kw",
38990         "965"
38991       ],
38992       [
38993         "Kyrgyzstan (Кыргызстан)",
38994         "kg",
38995         "996"
38996       ],
38997       [
38998         "Laos (ລາວ)",
38999         "la",
39000         "856"
39001       ],
39002       [
39003         "Latvia (Latvija)",
39004         "lv",
39005         "371"
39006       ],
39007       [
39008         "Lebanon (‫لبنان‬‎)",
39009         "lb",
39010         "961"
39011       ],
39012       [
39013         "Lesotho",
39014         "ls",
39015         "266"
39016       ],
39017       [
39018         "Liberia",
39019         "lr",
39020         "231"
39021       ],
39022       [
39023         "Libya (‫ليبيا‬‎)",
39024         "ly",
39025         "218"
39026       ],
39027       [
39028         "Liechtenstein",
39029         "li",
39030         "423"
39031       ],
39032       [
39033         "Lithuania (Lietuva)",
39034         "lt",
39035         "370"
39036       ],
39037       [
39038         "Luxembourg",
39039         "lu",
39040         "352"
39041       ],
39042       [
39043         "Macau (澳門)",
39044         "mo",
39045         "853"
39046       ],
39047       [
39048         "Macedonia (FYROM) (Македонија)",
39049         "mk",
39050         "389"
39051       ],
39052       [
39053         "Madagascar (Madagasikara)",
39054         "mg",
39055         "261"
39056       ],
39057       [
39058         "Malawi",
39059         "mw",
39060         "265"
39061       ],
39062       [
39063         "Malaysia",
39064         "my",
39065         "60"
39066       ],
39067       [
39068         "Maldives",
39069         "mv",
39070         "960"
39071       ],
39072       [
39073         "Mali",
39074         "ml",
39075         "223"
39076       ],
39077       [
39078         "Malta",
39079         "mt",
39080         "356"
39081       ],
39082       [
39083         "Marshall Islands",
39084         "mh",
39085         "692"
39086       ],
39087       [
39088         "Martinique",
39089         "mq",
39090         "596"
39091       ],
39092       [
39093         "Mauritania (‫موريتانيا‬‎)",
39094         "mr",
39095         "222"
39096       ],
39097       [
39098         "Mauritius (Moris)",
39099         "mu",
39100         "230"
39101       ],
39102       [
39103         "Mayotte",
39104         "yt",
39105         "262",
39106         1
39107       ],
39108       [
39109         "Mexico (México)",
39110         "mx",
39111         "52"
39112       ],
39113       [
39114         "Micronesia",
39115         "fm",
39116         "691"
39117       ],
39118       [
39119         "Moldova (Republica Moldova)",
39120         "md",
39121         "373"
39122       ],
39123       [
39124         "Monaco",
39125         "mc",
39126         "377"
39127       ],
39128       [
39129         "Mongolia (Монгол)",
39130         "mn",
39131         "976"
39132       ],
39133       [
39134         "Montenegro (Crna Gora)",
39135         "me",
39136         "382"
39137       ],
39138       [
39139         "Montserrat",
39140         "ms",
39141         "1664"
39142       ],
39143       [
39144         "Morocco (‫المغرب‬‎)",
39145         "ma",
39146         "212",
39147         0
39148       ],
39149       [
39150         "Mozambique (Moçambique)",
39151         "mz",
39152         "258"
39153       ],
39154       [
39155         "Myanmar (Burma) (မြန်မာ)",
39156         "mm",
39157         "95"
39158       ],
39159       [
39160         "Namibia (Namibië)",
39161         "na",
39162         "264"
39163       ],
39164       [
39165         "Nauru",
39166         "nr",
39167         "674"
39168       ],
39169       [
39170         "Nepal (नेपाल)",
39171         "np",
39172         "977"
39173       ],
39174       [
39175         "Netherlands (Nederland)",
39176         "nl",
39177         "31"
39178       ],
39179       [
39180         "New Caledonia (Nouvelle-Calédonie)",
39181         "nc",
39182         "687"
39183       ],
39184       [
39185         "New Zealand",
39186         "nz",
39187         "64"
39188       ],
39189       [
39190         "Nicaragua",
39191         "ni",
39192         "505"
39193       ],
39194       [
39195         "Niger (Nijar)",
39196         "ne",
39197         "227"
39198       ],
39199       [
39200         "Nigeria",
39201         "ng",
39202         "234"
39203       ],
39204       [
39205         "Niue",
39206         "nu",
39207         "683"
39208       ],
39209       [
39210         "Norfolk Island",
39211         "nf",
39212         "672"
39213       ],
39214       [
39215         "North Korea (조선 민주주의 인민 공화국)",
39216         "kp",
39217         "850"
39218       ],
39219       [
39220         "Northern Mariana Islands",
39221         "mp",
39222         "1670"
39223       ],
39224       [
39225         "Norway (Norge)",
39226         "no",
39227         "47",
39228         0
39229       ],
39230       [
39231         "Oman (‫عُمان‬‎)",
39232         "om",
39233         "968"
39234       ],
39235       [
39236         "Pakistan (‫پاکستان‬‎)",
39237         "pk",
39238         "92"
39239       ],
39240       [
39241         "Palau",
39242         "pw",
39243         "680"
39244       ],
39245       [
39246         "Palestine (‫فلسطين‬‎)",
39247         "ps",
39248         "970"
39249       ],
39250       [
39251         "Panama (Panamá)",
39252         "pa",
39253         "507"
39254       ],
39255       [
39256         "Papua New Guinea",
39257         "pg",
39258         "675"
39259       ],
39260       [
39261         "Paraguay",
39262         "py",
39263         "595"
39264       ],
39265       [
39266         "Peru (Perú)",
39267         "pe",
39268         "51"
39269       ],
39270       [
39271         "Philippines",
39272         "ph",
39273         "63"
39274       ],
39275       [
39276         "Poland (Polska)",
39277         "pl",
39278         "48"
39279       ],
39280       [
39281         "Portugal",
39282         "pt",
39283         "351"
39284       ],
39285       [
39286         "Puerto Rico",
39287         "pr",
39288         "1",
39289         3,
39290         ["787", "939"]
39291       ],
39292       [
39293         "Qatar (‫قطر‬‎)",
39294         "qa",
39295         "974"
39296       ],
39297       [
39298         "Réunion (La Réunion)",
39299         "re",
39300         "262",
39301         0
39302       ],
39303       [
39304         "Romania (România)",
39305         "ro",
39306         "40"
39307       ],
39308       [
39309         "Russia (Россия)",
39310         "ru",
39311         "7",
39312         0
39313       ],
39314       [
39315         "Rwanda",
39316         "rw",
39317         "250"
39318       ],
39319       [
39320         "Saint Barthélemy",
39321         "bl",
39322         "590",
39323         1
39324       ],
39325       [
39326         "Saint Helena",
39327         "sh",
39328         "290"
39329       ],
39330       [
39331         "Saint Kitts and Nevis",
39332         "kn",
39333         "1869"
39334       ],
39335       [
39336         "Saint Lucia",
39337         "lc",
39338         "1758"
39339       ],
39340       [
39341         "Saint Martin (Saint-Martin (partie française))",
39342         "mf",
39343         "590",
39344         2
39345       ],
39346       [
39347         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39348         "pm",
39349         "508"
39350       ],
39351       [
39352         "Saint Vincent and the Grenadines",
39353         "vc",
39354         "1784"
39355       ],
39356       [
39357         "Samoa",
39358         "ws",
39359         "685"
39360       ],
39361       [
39362         "San Marino",
39363         "sm",
39364         "378"
39365       ],
39366       [
39367         "São Tomé and Príncipe (São Tomé e Príncipe)",
39368         "st",
39369         "239"
39370       ],
39371       [
39372         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39373         "sa",
39374         "966"
39375       ],
39376       [
39377         "Senegal (Sénégal)",
39378         "sn",
39379         "221"
39380       ],
39381       [
39382         "Serbia (Србија)",
39383         "rs",
39384         "381"
39385       ],
39386       [
39387         "Seychelles",
39388         "sc",
39389         "248"
39390       ],
39391       [
39392         "Sierra Leone",
39393         "sl",
39394         "232"
39395       ],
39396       [
39397         "Singapore",
39398         "sg",
39399         "65"
39400       ],
39401       [
39402         "Sint Maarten",
39403         "sx",
39404         "1721"
39405       ],
39406       [
39407         "Slovakia (Slovensko)",
39408         "sk",
39409         "421"
39410       ],
39411       [
39412         "Slovenia (Slovenija)",
39413         "si",
39414         "386"
39415       ],
39416       [
39417         "Solomon Islands",
39418         "sb",
39419         "677"
39420       ],
39421       [
39422         "Somalia (Soomaaliya)",
39423         "so",
39424         "252"
39425       ],
39426       [
39427         "South Africa",
39428         "za",
39429         "27"
39430       ],
39431       [
39432         "South Korea (대한민국)",
39433         "kr",
39434         "82"
39435       ],
39436       [
39437         "South Sudan (‫جنوب السودان‬‎)",
39438         "ss",
39439         "211"
39440       ],
39441       [
39442         "Spain (España)",
39443         "es",
39444         "34"
39445       ],
39446       [
39447         "Sri Lanka (ශ්‍රී ලංකාව)",
39448         "lk",
39449         "94"
39450       ],
39451       [
39452         "Sudan (‫السودان‬‎)",
39453         "sd",
39454         "249"
39455       ],
39456       [
39457         "Suriname",
39458         "sr",
39459         "597"
39460       ],
39461       [
39462         "Svalbard and Jan Mayen",
39463         "sj",
39464         "47",
39465         1
39466       ],
39467       [
39468         "Swaziland",
39469         "sz",
39470         "268"
39471       ],
39472       [
39473         "Sweden (Sverige)",
39474         "se",
39475         "46"
39476       ],
39477       [
39478         "Switzerland (Schweiz)",
39479         "ch",
39480         "41"
39481       ],
39482       [
39483         "Syria (‫سوريا‬‎)",
39484         "sy",
39485         "963"
39486       ],
39487       [
39488         "Taiwan (台灣)",
39489         "tw",
39490         "886"
39491       ],
39492       [
39493         "Tajikistan",
39494         "tj",
39495         "992"
39496       ],
39497       [
39498         "Tanzania",
39499         "tz",
39500         "255"
39501       ],
39502       [
39503         "Thailand (ไทย)",
39504         "th",
39505         "66"
39506       ],
39507       [
39508         "Timor-Leste",
39509         "tl",
39510         "670"
39511       ],
39512       [
39513         "Togo",
39514         "tg",
39515         "228"
39516       ],
39517       [
39518         "Tokelau",
39519         "tk",
39520         "690"
39521       ],
39522       [
39523         "Tonga",
39524         "to",
39525         "676"
39526       ],
39527       [
39528         "Trinidad and Tobago",
39529         "tt",
39530         "1868"
39531       ],
39532       [
39533         "Tunisia (‫تونس‬‎)",
39534         "tn",
39535         "216"
39536       ],
39537       [
39538         "Turkey (Türkiye)",
39539         "tr",
39540         "90"
39541       ],
39542       [
39543         "Turkmenistan",
39544         "tm",
39545         "993"
39546       ],
39547       [
39548         "Turks and Caicos Islands",
39549         "tc",
39550         "1649"
39551       ],
39552       [
39553         "Tuvalu",
39554         "tv",
39555         "688"
39556       ],
39557       [
39558         "U.S. Virgin Islands",
39559         "vi",
39560         "1340"
39561       ],
39562       [
39563         "Uganda",
39564         "ug",
39565         "256"
39566       ],
39567       [
39568         "Ukraine (Україна)",
39569         "ua",
39570         "380"
39571       ],
39572       [
39573         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39574         "ae",
39575         "971"
39576       ],
39577       [
39578         "United Kingdom",
39579         "gb",
39580         "44",
39581         0
39582       ],
39583       [
39584         "United States",
39585         "us",
39586         "1",
39587         0
39588       ],
39589       [
39590         "Uruguay",
39591         "uy",
39592         "598"
39593       ],
39594       [
39595         "Uzbekistan (Oʻzbekiston)",
39596         "uz",
39597         "998"
39598       ],
39599       [
39600         "Vanuatu",
39601         "vu",
39602         "678"
39603       ],
39604       [
39605         "Vatican City (Città del Vaticano)",
39606         "va",
39607         "39",
39608         1
39609       ],
39610       [
39611         "Venezuela",
39612         "ve",
39613         "58"
39614       ],
39615       [
39616         "Vietnam (Việt Nam)",
39617         "vn",
39618         "84"
39619       ],
39620       [
39621         "Wallis and Futuna (Wallis-et-Futuna)",
39622         "wf",
39623         "681"
39624       ],
39625       [
39626         "Western Sahara (‫الصحراء الغربية‬‎)",
39627         "eh",
39628         "212",
39629         1
39630       ],
39631       [
39632         "Yemen (‫اليمن‬‎)",
39633         "ye",
39634         "967"
39635       ],
39636       [
39637         "Zambia",
39638         "zm",
39639         "260"
39640       ],
39641       [
39642         "Zimbabwe",
39643         "zw",
39644         "263"
39645       ],
39646       [
39647         "Åland Islands",
39648         "ax",
39649         "358",
39650         1
39651       ]
39652   ];
39653   
39654   return d;
39655 }/**
39656 *    This script refer to:
39657 *    Title: International Telephone Input
39658 *    Author: Jack O'Connor
39659 *    Code version:  v12.1.12
39660 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39661 **/
39662
39663 /**
39664  * @class Roo.bootstrap.PhoneInput
39665  * @extends Roo.bootstrap.TriggerField
39666  * An input with International dial-code selection
39667  
39668  * @cfg {String} defaultDialCode default '+852'
39669  * @cfg {Array} preferedCountries default []
39670   
39671  * @constructor
39672  * Create a new PhoneInput.
39673  * @param {Object} config Configuration options
39674  */
39675
39676 Roo.bootstrap.PhoneInput = function(config) {
39677     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39678 };
39679
39680 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39681         
39682         listWidth: undefined,
39683         
39684         selectedClass: 'active',
39685         
39686         invalidClass : "has-warning",
39687         
39688         validClass: 'has-success',
39689         
39690         allowed: '0123456789',
39691         
39692         /**
39693          * @cfg {String} defaultDialCode The default dial code when initializing the input
39694          */
39695         defaultDialCode: '+852',
39696         
39697         /**
39698          * @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
39699          */
39700         preferedCountries: false,
39701         
39702         getAutoCreate : function()
39703         {
39704             var data = Roo.bootstrap.PhoneInputData();
39705             var align = this.labelAlign || this.parentLabelAlign();
39706             var id = Roo.id();
39707             
39708             this.allCountries = [];
39709             this.dialCodeMapping = [];
39710             
39711             for (var i = 0; i < data.length; i++) {
39712               var c = data[i];
39713               this.allCountries[i] = {
39714                 name: c[0],
39715                 iso2: c[1],
39716                 dialCode: c[2],
39717                 priority: c[3] || 0,
39718                 areaCodes: c[4] || null
39719               };
39720               this.dialCodeMapping[c[2]] = {
39721                   name: c[0],
39722                   iso2: c[1],
39723                   priority: c[3] || 0,
39724                   areaCodes: c[4] || null
39725               };
39726             }
39727             
39728             var cfg = {
39729                 cls: 'form-group',
39730                 cn: []
39731             };
39732             
39733             var input =  {
39734                 tag: 'input',
39735                 id : id,
39736                 cls : 'form-control tel-input',
39737                 autocomplete: 'new-password'
39738             };
39739             
39740             var hiddenInput = {
39741                 tag: 'input',
39742                 type: 'hidden',
39743                 cls: 'hidden-tel-input'
39744             };
39745             
39746             if (this.name) {
39747                 hiddenInput.name = this.name;
39748             }
39749             
39750             if (this.disabled) {
39751                 input.disabled = true;
39752             }
39753             
39754             var flag_container = {
39755                 tag: 'div',
39756                 cls: 'flag-box',
39757                 cn: [
39758                     {
39759                         tag: 'div',
39760                         cls: 'flag'
39761                     },
39762                     {
39763                         tag: 'div',
39764                         cls: 'caret'
39765                     }
39766                 ]
39767             };
39768             
39769             var box = {
39770                 tag: 'div',
39771                 cls: this.hasFeedback ? 'has-feedback' : '',
39772                 cn: [
39773                     hiddenInput,
39774                     input,
39775                     {
39776                         tag: 'input',
39777                         cls: 'dial-code-holder',
39778                         disabled: true
39779                     }
39780                 ]
39781             };
39782             
39783             var container = {
39784                 cls: 'roo-select2-container input-group',
39785                 cn: [
39786                     flag_container,
39787                     box
39788                 ]
39789             };
39790             
39791             if (this.fieldLabel.length) {
39792                 var indicator = {
39793                     tag: 'i',
39794                     tooltip: 'This field is required'
39795                 };
39796                 
39797                 var label = {
39798                     tag: 'label',
39799                     'for':  id,
39800                     cls: 'control-label',
39801                     cn: []
39802                 };
39803                 
39804                 var label_text = {
39805                     tag: 'span',
39806                     html: this.fieldLabel
39807                 };
39808                 
39809                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39810                 label.cn = [
39811                     indicator,
39812                     label_text
39813                 ];
39814                 
39815                 if(this.indicatorpos == 'right') {
39816                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39817                     label.cn = [
39818                         label_text,
39819                         indicator
39820                     ];
39821                 }
39822                 
39823                 if(align == 'left') {
39824                     container = {
39825                         tag: 'div',
39826                         cn: [
39827                             container
39828                         ]
39829                     };
39830                     
39831                     if(this.labelWidth > 12){
39832                         label.style = "width: " + this.labelWidth + 'px';
39833                     }
39834                     if(this.labelWidth < 13 && this.labelmd == 0){
39835                         this.labelmd = this.labelWidth;
39836                     }
39837                     if(this.labellg > 0){
39838                         label.cls += ' col-lg-' + this.labellg;
39839                         input.cls += ' col-lg-' + (12 - this.labellg);
39840                     }
39841                     if(this.labelmd > 0){
39842                         label.cls += ' col-md-' + this.labelmd;
39843                         container.cls += ' col-md-' + (12 - this.labelmd);
39844                     }
39845                     if(this.labelsm > 0){
39846                         label.cls += ' col-sm-' + this.labelsm;
39847                         container.cls += ' col-sm-' + (12 - this.labelsm);
39848                     }
39849                     if(this.labelxs > 0){
39850                         label.cls += ' col-xs-' + this.labelxs;
39851                         container.cls += ' col-xs-' + (12 - this.labelxs);
39852                     }
39853                 }
39854             }
39855             
39856             cfg.cn = [
39857                 label,
39858                 container
39859             ];
39860             
39861             var settings = this;
39862             
39863             ['xs','sm','md','lg'].map(function(size){
39864                 if (settings[size]) {
39865                     cfg.cls += ' col-' + size + '-' + settings[size];
39866                 }
39867             });
39868             
39869             this.store = new Roo.data.Store({
39870                 proxy : new Roo.data.MemoryProxy({}),
39871                 reader : new Roo.data.JsonReader({
39872                     fields : [
39873                         {
39874                             'name' : 'name',
39875                             'type' : 'string'
39876                         },
39877                         {
39878                             'name' : 'iso2',
39879                             'type' : 'string'
39880                         },
39881                         {
39882                             'name' : 'dialCode',
39883                             'type' : 'string'
39884                         },
39885                         {
39886                             'name' : 'priority',
39887                             'type' : 'string'
39888                         },
39889                         {
39890                             'name' : 'areaCodes',
39891                             'type' : 'string'
39892                         }
39893                     ]
39894                 })
39895             });
39896             
39897             if(!this.preferedCountries) {
39898                 this.preferedCountries = [
39899                     'hk',
39900                     'gb',
39901                     'us'
39902                 ];
39903             }
39904             
39905             var p = this.preferedCountries.reverse();
39906             
39907             if(p) {
39908                 for (var i = 0; i < p.length; i++) {
39909                     for (var j = 0; j < this.allCountries.length; j++) {
39910                         if(this.allCountries[j].iso2 == p[i]) {
39911                             var t = this.allCountries[j];
39912                             this.allCountries.splice(j,1);
39913                             this.allCountries.unshift(t);
39914                         }
39915                     } 
39916                 }
39917             }
39918             
39919             this.store.proxy.data = {
39920                 success: true,
39921                 data: this.allCountries
39922             };
39923             
39924             return cfg;
39925         },
39926         
39927         initEvents : function()
39928         {
39929             this.createList();
39930             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39931             
39932             this.indicator = this.indicatorEl();
39933             this.flag = this.flagEl();
39934             this.dialCodeHolder = this.dialCodeHolderEl();
39935             
39936             this.trigger = this.el.select('div.flag-box',true).first();
39937             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39938             
39939             var _this = this;
39940             
39941             (function(){
39942                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39943                 _this.list.setWidth(lw);
39944             }).defer(100);
39945             
39946             this.list.on('mouseover', this.onViewOver, this);
39947             this.list.on('mousemove', this.onViewMove, this);
39948             this.inputEl().on("keyup", this.onKeyUp, this);
39949             
39950             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39951
39952             this.view = new Roo.View(this.list, this.tpl, {
39953                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39954             });
39955             
39956             this.view.on('click', this.onViewClick, this);
39957             this.setValue(this.defaultDialCode);
39958         },
39959         
39960         onTriggerClick : function(e)
39961         {
39962             Roo.log('trigger click');
39963             if(this.disabled){
39964                 return;
39965             }
39966             
39967             if(this.isExpanded()){
39968                 this.collapse();
39969                 this.hasFocus = false;
39970             }else {
39971                 this.store.load({});
39972                 this.hasFocus = true;
39973                 this.expand();
39974             }
39975         },
39976         
39977         isExpanded : function()
39978         {
39979             return this.list.isVisible();
39980         },
39981         
39982         collapse : function()
39983         {
39984             if(!this.isExpanded()){
39985                 return;
39986             }
39987             this.list.hide();
39988             Roo.get(document).un('mousedown', this.collapseIf, this);
39989             Roo.get(document).un('mousewheel', this.collapseIf, this);
39990             this.fireEvent('collapse', this);
39991             this.validate();
39992         },
39993         
39994         expand : function()
39995         {
39996             Roo.log('expand');
39997
39998             if(this.isExpanded() || !this.hasFocus){
39999                 return;
40000             }
40001             
40002             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40003             this.list.setWidth(lw);
40004             
40005             this.list.show();
40006             this.restrictHeight();
40007             
40008             Roo.get(document).on('mousedown', this.collapseIf, this);
40009             Roo.get(document).on('mousewheel', this.collapseIf, this);
40010             
40011             this.fireEvent('expand', this);
40012         },
40013         
40014         restrictHeight : function()
40015         {
40016             this.list.alignTo(this.inputEl(), this.listAlign);
40017             this.list.alignTo(this.inputEl(), this.listAlign);
40018         },
40019         
40020         onViewOver : function(e, t)
40021         {
40022             if(this.inKeyMode){
40023                 return;
40024             }
40025             var item = this.view.findItemFromChild(t);
40026             
40027             if(item){
40028                 var index = this.view.indexOf(item);
40029                 this.select(index, false);
40030             }
40031         },
40032
40033         // private
40034         onViewClick : function(view, doFocus, el, e)
40035         {
40036             var index = this.view.getSelectedIndexes()[0];
40037             
40038             var r = this.store.getAt(index);
40039             
40040             if(r){
40041                 this.onSelect(r, index);
40042             }
40043             if(doFocus !== false && !this.blockFocus){
40044                 this.inputEl().focus();
40045             }
40046         },
40047         
40048         onViewMove : function(e, t)
40049         {
40050             this.inKeyMode = false;
40051         },
40052         
40053         select : function(index, scrollIntoView)
40054         {
40055             this.selectedIndex = index;
40056             this.view.select(index);
40057             if(scrollIntoView !== false){
40058                 var el = this.view.getNode(index);
40059                 if(el){
40060                     this.list.scrollChildIntoView(el, false);
40061                 }
40062             }
40063         },
40064         
40065         createList : function()
40066         {
40067             this.list = Roo.get(document.body).createChild({
40068                 tag: 'ul',
40069                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40070                 style: 'display:none'
40071             });
40072             
40073             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40074         },
40075         
40076         collapseIf : function(e)
40077         {
40078             var in_combo  = e.within(this.el);
40079             var in_list =  e.within(this.list);
40080             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40081             
40082             if (in_combo || in_list || is_list) {
40083                 return;
40084             }
40085             this.collapse();
40086         },
40087         
40088         onSelect : function(record, index)
40089         {
40090             if(this.fireEvent('beforeselect', this, record, index) !== false){
40091                 
40092                 this.setFlagClass(record.data.iso2);
40093                 this.setDialCode(record.data.dialCode);
40094                 this.hasFocus = false;
40095                 this.collapse();
40096                 this.fireEvent('select', this, record, index);
40097             }
40098         },
40099         
40100         flagEl : function()
40101         {
40102             var flag = this.el.select('div.flag',true).first();
40103             if(!flag){
40104                 return false;
40105             }
40106             return flag;
40107         },
40108         
40109         dialCodeHolderEl : function()
40110         {
40111             var d = this.el.select('input.dial-code-holder',true).first();
40112             if(!d){
40113                 return false;
40114             }
40115             return d;
40116         },
40117         
40118         setDialCode : function(v)
40119         {
40120             this.dialCodeHolder.dom.value = '+'+v;
40121         },
40122         
40123         setFlagClass : function(n)
40124         {
40125             this.flag.dom.className = 'flag '+n;
40126         },
40127         
40128         getValue : function()
40129         {
40130             var v = this.inputEl().getValue();
40131             if(this.dialCodeHolder) {
40132                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40133             }
40134             return v;
40135         },
40136         
40137         setValue : function(v)
40138         {
40139             var d = this.getDialCode(v);
40140             
40141             //invalid dial code
40142             if(v.length == 0 || !d || d.length == 0) {
40143                 if(this.rendered){
40144                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40145                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40146                 }
40147                 return;
40148             }
40149             
40150             //valid dial code
40151             this.setFlagClass(this.dialCodeMapping[d].iso2);
40152             this.setDialCode(d);
40153             this.inputEl().dom.value = v.replace('+'+d,'');
40154             this.hiddenEl().dom.value = this.getValue();
40155             
40156             this.validate();
40157         },
40158         
40159         getDialCode : function(v)
40160         {
40161             v = v ||  '';
40162             
40163             if (v.length == 0) {
40164                 return this.dialCodeHolder.dom.value;
40165             }
40166             
40167             var dialCode = "";
40168             if (v.charAt(0) != "+") {
40169                 return false;
40170             }
40171             var numericChars = "";
40172             for (var i = 1; i < v.length; i++) {
40173               var c = v.charAt(i);
40174               if (!isNaN(c)) {
40175                 numericChars += c;
40176                 if (this.dialCodeMapping[numericChars]) {
40177                   dialCode = v.substr(1, i);
40178                 }
40179                 if (numericChars.length == 4) {
40180                   break;
40181                 }
40182               }
40183             }
40184             return dialCode;
40185         },
40186         
40187         reset : function()
40188         {
40189             this.setValue(this.defaultDialCode);
40190             this.validate();
40191         },
40192         
40193         hiddenEl : function()
40194         {
40195             return this.el.select('input.hidden-tel-input',true).first();
40196         },
40197         
40198         onKeyUp : function(e){
40199             
40200             var k = e.getKey();
40201             var c = e.getCharCode();
40202             
40203             if(
40204                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40205                     this.allowed.indexOf(String.fromCharCode(c)) === -1
40206             ){
40207                 e.stopEvent();
40208             }
40209             
40210             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40211             //     return;
40212             // }
40213             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40214                 e.stopEvent();
40215             }
40216             
40217             this.setValue(this.getValue());
40218         }
40219         
40220 });
40221 /**
40222  * @class Roo.bootstrap.MoneyField
40223  * @extends Roo.bootstrap.ComboBox
40224  * Bootstrap MoneyField class
40225  * 
40226  * @constructor
40227  * Create a new MoneyField.
40228  * @param {Object} config Configuration options
40229  */
40230
40231 Roo.bootstrap.MoneyField = function(config) {
40232     
40233     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40234     
40235 };
40236
40237 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40238     
40239     /**
40240      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40241      */
40242     allowDecimals : true,
40243     /**
40244      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40245      */
40246     decimalSeparator : ".",
40247     /**
40248      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40249      */
40250     decimalPrecision : 0,
40251     /**
40252      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40253      */
40254     allowNegative : true,
40255     /**
40256      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40257      */
40258     allowZero: true,
40259     /**
40260      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40261      */
40262     minValue : Number.NEGATIVE_INFINITY,
40263     /**
40264      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40265      */
40266     maxValue : Number.MAX_VALUE,
40267     /**
40268      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40269      */
40270     minText : "The minimum value for this field is {0}",
40271     /**
40272      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40273      */
40274     maxText : "The maximum value for this field is {0}",
40275     /**
40276      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
40277      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40278      */
40279     nanText : "{0} is not a valid number",
40280     /**
40281      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40282      */
40283     castInt : true,
40284     /**
40285      * @cfg {String} defaults currency of the MoneyField
40286      * value should be in lkey
40287      */
40288     defaultCurrency : false,
40289     /**
40290      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40291      */
40292     thousandsDelimiter : false,
40293     
40294     
40295     inputlg : 9,
40296     inputmd : 9,
40297     inputsm : 9,
40298     inputxs : 6,
40299     
40300     store : false,
40301     
40302     getAutoCreate : function()
40303     {
40304         var align = this.labelAlign || this.parentLabelAlign();
40305         
40306         var id = Roo.id();
40307
40308         var cfg = {
40309             cls: 'form-group',
40310             cn: []
40311         };
40312
40313         var input =  {
40314             tag: 'input',
40315             id : id,
40316             cls : 'form-control roo-money-amount-input',
40317             autocomplete: 'new-password'
40318         };
40319         
40320         var hiddenInput = {
40321             tag: 'input',
40322             type: 'hidden',
40323             id: Roo.id(),
40324             cls: 'hidden-number-input'
40325         };
40326         
40327         if (this.name) {
40328             hiddenInput.name = this.name;
40329         }
40330
40331         if (this.disabled) {
40332             input.disabled = true;
40333         }
40334
40335         var clg = 12 - this.inputlg;
40336         var cmd = 12 - this.inputmd;
40337         var csm = 12 - this.inputsm;
40338         var cxs = 12 - this.inputxs;
40339         
40340         var container = {
40341             tag : 'div',
40342             cls : 'row roo-money-field',
40343             cn : [
40344                 {
40345                     tag : 'div',
40346                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40347                     cn : [
40348                         {
40349                             tag : 'div',
40350                             cls: 'roo-select2-container input-group',
40351                             cn: [
40352                                 {
40353                                     tag : 'input',
40354                                     cls : 'form-control roo-money-currency-input',
40355                                     autocomplete: 'new-password',
40356                                     readOnly : 1,
40357                                     name : this.currencyName
40358                                 },
40359                                 {
40360                                     tag :'span',
40361                                     cls : 'input-group-addon',
40362                                     cn : [
40363                                         {
40364                                             tag: 'span',
40365                                             cls: 'caret'
40366                                         }
40367                                     ]
40368                                 }
40369                             ]
40370                         }
40371                     ]
40372                 },
40373                 {
40374                     tag : 'div',
40375                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40376                     cn : [
40377                         {
40378                             tag: 'div',
40379                             cls: this.hasFeedback ? 'has-feedback' : '',
40380                             cn: [
40381                                 input
40382                             ]
40383                         }
40384                     ]
40385                 }
40386             ]
40387             
40388         };
40389         
40390         if (this.fieldLabel.length) {
40391             var indicator = {
40392                 tag: 'i',
40393                 tooltip: 'This field is required'
40394             };
40395
40396             var label = {
40397                 tag: 'label',
40398                 'for':  id,
40399                 cls: 'control-label',
40400                 cn: []
40401             };
40402
40403             var label_text = {
40404                 tag: 'span',
40405                 html: this.fieldLabel
40406             };
40407
40408             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40409             label.cn = [
40410                 indicator,
40411                 label_text
40412             ];
40413
40414             if(this.indicatorpos == 'right') {
40415                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40416                 label.cn = [
40417                     label_text,
40418                     indicator
40419                 ];
40420             }
40421
40422             if(align == 'left') {
40423                 container = {
40424                     tag: 'div',
40425                     cn: [
40426                         container
40427                     ]
40428                 };
40429
40430                 if(this.labelWidth > 12){
40431                     label.style = "width: " + this.labelWidth + 'px';
40432                 }
40433                 if(this.labelWidth < 13 && this.labelmd == 0){
40434                     this.labelmd = this.labelWidth;
40435                 }
40436                 if(this.labellg > 0){
40437                     label.cls += ' col-lg-' + this.labellg;
40438                     input.cls += ' col-lg-' + (12 - this.labellg);
40439                 }
40440                 if(this.labelmd > 0){
40441                     label.cls += ' col-md-' + this.labelmd;
40442                     container.cls += ' col-md-' + (12 - this.labelmd);
40443                 }
40444                 if(this.labelsm > 0){
40445                     label.cls += ' col-sm-' + this.labelsm;
40446                     container.cls += ' col-sm-' + (12 - this.labelsm);
40447                 }
40448                 if(this.labelxs > 0){
40449                     label.cls += ' col-xs-' + this.labelxs;
40450                     container.cls += ' col-xs-' + (12 - this.labelxs);
40451                 }
40452             }
40453         }
40454
40455         cfg.cn = [
40456             label,
40457             container,
40458             hiddenInput
40459         ];
40460         
40461         var settings = this;
40462
40463         ['xs','sm','md','lg'].map(function(size){
40464             if (settings[size]) {
40465                 cfg.cls += ' col-' + size + '-' + settings[size];
40466             }
40467         });
40468         
40469         return cfg;
40470     },
40471     
40472     initEvents : function()
40473     {
40474         this.indicator = this.indicatorEl();
40475         
40476         this.initCurrencyEvent();
40477         
40478         this.initNumberEvent();
40479     },
40480     
40481     initCurrencyEvent : function()
40482     {
40483         if (!this.store) {
40484             throw "can not find store for combo";
40485         }
40486         
40487         this.store = Roo.factory(this.store, Roo.data);
40488         this.store.parent = this;
40489         
40490         this.createList();
40491         
40492         this.triggerEl = this.el.select('.input-group-addon', true).first();
40493         
40494         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40495         
40496         var _this = this;
40497         
40498         (function(){
40499             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40500             _this.list.setWidth(lw);
40501         }).defer(100);
40502         
40503         this.list.on('mouseover', this.onViewOver, this);
40504         this.list.on('mousemove', this.onViewMove, this);
40505         this.list.on('scroll', this.onViewScroll, this);
40506         
40507         if(!this.tpl){
40508             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40509         }
40510         
40511         this.view = new Roo.View(this.list, this.tpl, {
40512             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40513         });
40514         
40515         this.view.on('click', this.onViewClick, this);
40516         
40517         this.store.on('beforeload', this.onBeforeLoad, this);
40518         this.store.on('load', this.onLoad, this);
40519         this.store.on('loadexception', this.onLoadException, this);
40520         
40521         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40522             "up" : function(e){
40523                 this.inKeyMode = true;
40524                 this.selectPrev();
40525             },
40526
40527             "down" : function(e){
40528                 if(!this.isExpanded()){
40529                     this.onTriggerClick();
40530                 }else{
40531                     this.inKeyMode = true;
40532                     this.selectNext();
40533                 }
40534             },
40535
40536             "enter" : function(e){
40537                 this.collapse();
40538                 
40539                 if(this.fireEvent("specialkey", this, e)){
40540                     this.onViewClick(false);
40541                 }
40542                 
40543                 return true;
40544             },
40545
40546             "esc" : function(e){
40547                 this.collapse();
40548             },
40549
40550             "tab" : function(e){
40551                 this.collapse();
40552                 
40553                 if(this.fireEvent("specialkey", this, e)){
40554                     this.onViewClick(false);
40555                 }
40556                 
40557                 return true;
40558             },
40559
40560             scope : this,
40561
40562             doRelay : function(foo, bar, hname){
40563                 if(hname == 'down' || this.scope.isExpanded()){
40564                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40565                 }
40566                 return true;
40567             },
40568
40569             forceKeyDown: true
40570         });
40571         
40572         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40573         
40574     },
40575     
40576     initNumberEvent : function(e)
40577     {
40578         this.inputEl().on("keydown" , this.fireKey,  this);
40579         this.inputEl().on("focus", this.onFocus,  this);
40580         this.inputEl().on("blur", this.onBlur,  this);
40581         
40582         this.inputEl().relayEvent('keyup', this);
40583         
40584         if(this.indicator){
40585             this.indicator.addClass('invisible');
40586         }
40587  
40588         this.originalValue = this.getValue();
40589         
40590         if(this.validationEvent == 'keyup'){
40591             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40592             this.inputEl().on('keyup', this.filterValidation, this);
40593         }
40594         else if(this.validationEvent !== false){
40595             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40596         }
40597         
40598         if(this.selectOnFocus){
40599             this.on("focus", this.preFocus, this);
40600             
40601         }
40602         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40603             this.inputEl().on("keypress", this.filterKeys, this);
40604         } else {
40605             this.inputEl().relayEvent('keypress', this);
40606         }
40607         
40608         var allowed = "0123456789";
40609         
40610         if(this.allowDecimals){
40611             allowed += this.decimalSeparator;
40612         }
40613         
40614         if(this.allowNegative){
40615             allowed += "-";
40616         }
40617         
40618         if(this.thousandsDelimiter) {
40619             allowed += ",";
40620         }
40621         
40622         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40623         
40624         var keyPress = function(e){
40625             
40626             var k = e.getKey();
40627             
40628             var c = e.getCharCode();
40629             
40630             if(
40631                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40632                     allowed.indexOf(String.fromCharCode(c)) === -1
40633             ){
40634                 e.stopEvent();
40635                 return;
40636             }
40637             
40638             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40639                 return;
40640             }
40641             
40642             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40643                 e.stopEvent();
40644             }
40645         };
40646         
40647         this.inputEl().on("keypress", keyPress, this);
40648         
40649     },
40650     
40651     onTriggerClick : function(e)
40652     {   
40653         if(this.disabled){
40654             return;
40655         }
40656         
40657         this.page = 0;
40658         this.loadNext = false;
40659         
40660         if(this.isExpanded()){
40661             this.collapse();
40662             return;
40663         }
40664         
40665         this.hasFocus = true;
40666         
40667         if(this.triggerAction == 'all') {
40668             this.doQuery(this.allQuery, true);
40669             return;
40670         }
40671         
40672         this.doQuery(this.getRawValue());
40673     },
40674     
40675     getCurrency : function()
40676     {   
40677         var v = this.currencyEl().getValue();
40678         
40679         return v;
40680     },
40681     
40682     restrictHeight : function()
40683     {
40684         this.list.alignTo(this.currencyEl(), this.listAlign);
40685         this.list.alignTo(this.currencyEl(), this.listAlign);
40686     },
40687     
40688     onViewClick : function(view, doFocus, el, e)
40689     {
40690         var index = this.view.getSelectedIndexes()[0];
40691         
40692         var r = this.store.getAt(index);
40693         
40694         if(r){
40695             this.onSelect(r, index);
40696         }
40697     },
40698     
40699     onSelect : function(record, index){
40700         
40701         if(this.fireEvent('beforeselect', this, record, index) !== false){
40702         
40703             this.setFromCurrencyData(index > -1 ? record.data : false);
40704             
40705             this.collapse();
40706             
40707             this.fireEvent('select', this, record, index);
40708         }
40709     },
40710     
40711     setFromCurrencyData : function(o)
40712     {
40713         var currency = '';
40714         
40715         this.lastCurrency = o;
40716         
40717         if (this.currencyField) {
40718             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40719         } else {
40720             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40721         }
40722         
40723         this.lastSelectionText = currency;
40724         
40725         //setting default currency
40726         if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40727             this.setCurrency(this.defaultCurrency);
40728             return;
40729         }
40730         
40731         this.setCurrency(currency);
40732     },
40733     
40734     setFromData : function(o)
40735     {
40736         var c = {};
40737         
40738         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40739         
40740         this.setFromCurrencyData(c);
40741         
40742         var value = '';
40743         
40744         if (this.name) {
40745             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40746         } else {
40747             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40748         }
40749         
40750         this.setValue(value);
40751         
40752     },
40753     
40754     setCurrency : function(v)
40755     {   
40756         this.currencyValue = v;
40757         
40758         if(this.rendered){
40759             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40760             this.validate();
40761         }
40762     },
40763     
40764     setValue : function(v)
40765     {
40766         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40767         
40768         this.value = v;
40769         
40770         if(this.rendered){
40771             
40772             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40773             
40774             this.inputEl().dom.value = (v == '') ? '' :
40775                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40776             
40777             if(!this.allowZero && v === '0') {
40778                 this.hiddenEl().dom.value = '';
40779                 this.inputEl().dom.value = '';
40780             }
40781             
40782             this.validate();
40783         }
40784     },
40785     
40786     getRawValue : function()
40787     {
40788         var v = this.inputEl().getValue();
40789         
40790         return v;
40791     },
40792     
40793     getValue : function()
40794     {
40795         return this.fixPrecision(this.parseValue(this.getRawValue()));
40796     },
40797     
40798     parseValue : function(value)
40799     {
40800         if(this.thousandsDelimiter) {
40801             value += "";
40802             r = new RegExp(",", "g");
40803             value = value.replace(r, "");
40804         }
40805         
40806         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40807         return isNaN(value) ? '' : value;
40808         
40809     },
40810     
40811     fixPrecision : function(value)
40812     {
40813         if(this.thousandsDelimiter) {
40814             value += "";
40815             r = new RegExp(",", "g");
40816             value = value.replace(r, "");
40817         }
40818         
40819         var nan = isNaN(value);
40820         
40821         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40822             return nan ? '' : value;
40823         }
40824         return parseFloat(value).toFixed(this.decimalPrecision);
40825     },
40826     
40827     decimalPrecisionFcn : function(v)
40828     {
40829         return Math.floor(v);
40830     },
40831     
40832     validateValue : function(value)
40833     {
40834         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40835             return false;
40836         }
40837         
40838         var num = this.parseValue(value);
40839         
40840         if(isNaN(num)){
40841             this.markInvalid(String.format(this.nanText, value));
40842             return false;
40843         }
40844         
40845         if(num < this.minValue){
40846             this.markInvalid(String.format(this.minText, this.minValue));
40847             return false;
40848         }
40849         
40850         if(num > this.maxValue){
40851             this.markInvalid(String.format(this.maxText, this.maxValue));
40852             return false;
40853         }
40854         
40855         return true;
40856     },
40857     
40858     validate : function()
40859     {
40860         if(this.disabled || this.allowBlank){
40861             this.markValid();
40862             return true;
40863         }
40864         
40865         var currency = this.getCurrency();
40866         
40867         if(this.validateValue(this.getRawValue()) && currency.length){
40868             this.markValid();
40869             return true;
40870         }
40871         
40872         this.markInvalid();
40873         return false;
40874     },
40875     
40876     getName: function()
40877     {
40878         return this.name;
40879     },
40880     
40881     beforeBlur : function()
40882     {
40883         if(!this.castInt){
40884             return;
40885         }
40886         
40887         var v = this.parseValue(this.getRawValue());
40888         
40889         if(v || v == 0){
40890             this.setValue(v);
40891         }
40892     },
40893     
40894     onBlur : function()
40895     {
40896         this.beforeBlur();
40897         
40898         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40899             //this.el.removeClass(this.focusClass);
40900         }
40901         
40902         this.hasFocus = false;
40903         
40904         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40905             this.validate();
40906         }
40907         
40908         var v = this.getValue();
40909         
40910         if(String(v) !== String(this.startValue)){
40911             this.fireEvent('change', this, v, this.startValue);
40912         }
40913         
40914         this.fireEvent("blur", this);
40915     },
40916     
40917     inputEl : function()
40918     {
40919         return this.el.select('.roo-money-amount-input', true).first();
40920     },
40921     
40922     currencyEl : function()
40923     {
40924         return this.el.select('.roo-money-currency-input', true).first();
40925     },
40926     
40927     hiddenEl : function()
40928     {
40929         return this.el.select('input.hidden-number-input',true).first();
40930     }
40931     
40932 });