sync
[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} cursor (Optional)
5341      */
5342     /**
5343      * @cfg {String} tooltip (Optional)
5344      */
5345     /**
5346      * @cfg {Number} xs (Optional)
5347      */
5348     /**
5349      * @cfg {Number} sm (Optional)
5350      */
5351     /**
5352      * @cfg {Number} md (Optional)
5353      */
5354     /**
5355      * @cfg {Number} lg (Optional)
5356      */
5357     /**
5358      * Returns the id of the column at the specified index.
5359      * @param {Number} index The column index
5360      * @return {String} the id
5361      */
5362     getColumnId : function(index){
5363         return this.config[index].id;
5364     },
5365
5366     /**
5367      * Returns the column for a specified id.
5368      * @param {String} id The column id
5369      * @return {Object} the column
5370      */
5371     getColumnById : function(id){
5372         return this.lookup[id];
5373     },
5374
5375     
5376     /**
5377      * Returns the column for a specified dataIndex.
5378      * @param {String} dataIndex The column dataIndex
5379      * @return {Object|Boolean} the column or false if not found
5380      */
5381     getColumnByDataIndex: function(dataIndex){
5382         var index = this.findColumnIndex(dataIndex);
5383         return index > -1 ? this.config[index] : false;
5384     },
5385     
5386     /**
5387      * Returns the index for a specified column id.
5388      * @param {String} id The column id
5389      * @return {Number} the index, or -1 if not found
5390      */
5391     getIndexById : function(id){
5392         for(var i = 0, len = this.config.length; i < len; i++){
5393             if(this.config[i].id == id){
5394                 return i;
5395             }
5396         }
5397         return -1;
5398     },
5399     
5400     /**
5401      * Returns the index for a specified column dataIndex.
5402      * @param {String} dataIndex The column dataIndex
5403      * @return {Number} the index, or -1 if not found
5404      */
5405     
5406     findColumnIndex : function(dataIndex){
5407         for(var i = 0, len = this.config.length; i < len; i++){
5408             if(this.config[i].dataIndex == dataIndex){
5409                 return i;
5410             }
5411         }
5412         return -1;
5413     },
5414     
5415     
5416     moveColumn : function(oldIndex, newIndex){
5417         var c = this.config[oldIndex];
5418         this.config.splice(oldIndex, 1);
5419         this.config.splice(newIndex, 0, c);
5420         this.dataMap = null;
5421         this.fireEvent("columnmoved", this, oldIndex, newIndex);
5422     },
5423
5424     isLocked : function(colIndex){
5425         return this.config[colIndex].locked === true;
5426     },
5427
5428     setLocked : function(colIndex, value, suppressEvent){
5429         if(this.isLocked(colIndex) == value){
5430             return;
5431         }
5432         this.config[colIndex].locked = value;
5433         if(!suppressEvent){
5434             this.fireEvent("columnlockchange", this, colIndex, value);
5435         }
5436     },
5437
5438     getTotalLockedWidth : function(){
5439         var totalWidth = 0;
5440         for(var i = 0; i < this.config.length; i++){
5441             if(this.isLocked(i) && !this.isHidden(i)){
5442                 this.totalWidth += this.getColumnWidth(i);
5443             }
5444         }
5445         return totalWidth;
5446     },
5447
5448     getLockedCount : function(){
5449         for(var i = 0, len = this.config.length; i < len; i++){
5450             if(!this.isLocked(i)){
5451                 return i;
5452             }
5453         }
5454         
5455         return this.config.length;
5456     },
5457
5458     /**
5459      * Returns the number of columns.
5460      * @return {Number}
5461      */
5462     getColumnCount : function(visibleOnly){
5463         if(visibleOnly === true){
5464             var c = 0;
5465             for(var i = 0, len = this.config.length; i < len; i++){
5466                 if(!this.isHidden(i)){
5467                     c++;
5468                 }
5469             }
5470             return c;
5471         }
5472         return this.config.length;
5473     },
5474
5475     /**
5476      * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5477      * @param {Function} fn
5478      * @param {Object} scope (optional)
5479      * @return {Array} result
5480      */
5481     getColumnsBy : function(fn, scope){
5482         var r = [];
5483         for(var i = 0, len = this.config.length; i < len; i++){
5484             var c = this.config[i];
5485             if(fn.call(scope||this, c, i) === true){
5486                 r[r.length] = c;
5487             }
5488         }
5489         return r;
5490     },
5491
5492     /**
5493      * Returns true if the specified column is sortable.
5494      * @param {Number} col The column index
5495      * @return {Boolean}
5496      */
5497     isSortable : function(col){
5498         if(typeof this.config[col].sortable == "undefined"){
5499             return this.defaultSortable;
5500         }
5501         return this.config[col].sortable;
5502     },
5503
5504     /**
5505      * Returns the rendering (formatting) function defined for the column.
5506      * @param {Number} col The column index.
5507      * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5508      */
5509     getRenderer : function(col){
5510         if(!this.config[col].renderer){
5511             return Roo.grid.ColumnModel.defaultRenderer;
5512         }
5513         return this.config[col].renderer;
5514     },
5515
5516     /**
5517      * Sets the rendering (formatting) function for a column.
5518      * @param {Number} col The column index
5519      * @param {Function} fn The function to use to process the cell's raw data
5520      * to return HTML markup for the grid view. The render function is called with
5521      * the following parameters:<ul>
5522      * <li>Data value.</li>
5523      * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5524      * <li>css A CSS style string to apply to the table cell.</li>
5525      * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5526      * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5527      * <li>Row index</li>
5528      * <li>Column index</li>
5529      * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5530      */
5531     setRenderer : function(col, fn){
5532         this.config[col].renderer = fn;
5533     },
5534
5535     /**
5536      * Returns the width for the specified column.
5537      * @param {Number} col The column index
5538      * @return {Number}
5539      */
5540     getColumnWidth : function(col){
5541         return this.config[col].width * 1 || this.defaultWidth;
5542     },
5543
5544     /**
5545      * Sets the width for a column.
5546      * @param {Number} col The column index
5547      * @param {Number} width The new width
5548      */
5549     setColumnWidth : function(col, width, suppressEvent){
5550         this.config[col].width = width;
5551         this.totalWidth = null;
5552         if(!suppressEvent){
5553              this.fireEvent("widthchange", this, col, width);
5554         }
5555     },
5556
5557     /**
5558      * Returns the total width of all columns.
5559      * @param {Boolean} includeHidden True to include hidden column widths
5560      * @return {Number}
5561      */
5562     getTotalWidth : function(includeHidden){
5563         if(!this.totalWidth){
5564             this.totalWidth = 0;
5565             for(var i = 0, len = this.config.length; i < len; i++){
5566                 if(includeHidden || !this.isHidden(i)){
5567                     this.totalWidth += this.getColumnWidth(i);
5568                 }
5569             }
5570         }
5571         return this.totalWidth;
5572     },
5573
5574     /**
5575      * Returns the header for the specified column.
5576      * @param {Number} col The column index
5577      * @return {String}
5578      */
5579     getColumnHeader : function(col){
5580         return this.config[col].header;
5581     },
5582
5583     /**
5584      * Sets the header for a column.
5585      * @param {Number} col The column index
5586      * @param {String} header The new header
5587      */
5588     setColumnHeader : function(col, header){
5589         this.config[col].header = header;
5590         this.fireEvent("headerchange", this, col, header);
5591     },
5592
5593     /**
5594      * Returns the tooltip for the specified column.
5595      * @param {Number} col The column index
5596      * @return {String}
5597      */
5598     getColumnTooltip : function(col){
5599             return this.config[col].tooltip;
5600     },
5601     /**
5602      * Sets the tooltip for a column.
5603      * @param {Number} col The column index
5604      * @param {String} tooltip The new tooltip
5605      */
5606     setColumnTooltip : function(col, tooltip){
5607             this.config[col].tooltip = tooltip;
5608     },
5609
5610     /**
5611      * Returns the dataIndex for the specified column.
5612      * @param {Number} col The column index
5613      * @return {Number}
5614      */
5615     getDataIndex : function(col){
5616         return this.config[col].dataIndex;
5617     },
5618
5619     /**
5620      * Sets the dataIndex for a column.
5621      * @param {Number} col The column index
5622      * @param {Number} dataIndex The new dataIndex
5623      */
5624     setDataIndex : function(col, dataIndex){
5625         this.config[col].dataIndex = dataIndex;
5626     },
5627
5628     
5629     
5630     /**
5631      * Returns true if the cell is editable.
5632      * @param {Number} colIndex The column index
5633      * @param {Number} rowIndex The row index - this is nto actually used..?
5634      * @return {Boolean}
5635      */
5636     isCellEditable : function(colIndex, rowIndex){
5637         return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5638     },
5639
5640     /**
5641      * Returns the editor defined for the cell/column.
5642      * return false or null to disable editing.
5643      * @param {Number} colIndex The column index
5644      * @param {Number} rowIndex The row index
5645      * @return {Object}
5646      */
5647     getCellEditor : function(colIndex, rowIndex){
5648         return this.config[colIndex].editor;
5649     },
5650
5651     /**
5652      * Sets if a column is editable.
5653      * @param {Number} col The column index
5654      * @param {Boolean} editable True if the column is editable
5655      */
5656     setEditable : function(col, editable){
5657         this.config[col].editable = editable;
5658     },
5659
5660
5661     /**
5662      * Returns true if the column is hidden.
5663      * @param {Number} colIndex The column index
5664      * @return {Boolean}
5665      */
5666     isHidden : function(colIndex){
5667         return this.config[colIndex].hidden;
5668     },
5669
5670
5671     /**
5672      * Returns true if the column width cannot be changed
5673      */
5674     isFixed : function(colIndex){
5675         return this.config[colIndex].fixed;
5676     },
5677
5678     /**
5679      * Returns true if the column can be resized
5680      * @return {Boolean}
5681      */
5682     isResizable : function(colIndex){
5683         return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5684     },
5685     /**
5686      * Sets if a column is hidden.
5687      * @param {Number} colIndex The column index
5688      * @param {Boolean} hidden True if the column is hidden
5689      */
5690     setHidden : function(colIndex, hidden){
5691         this.config[colIndex].hidden = hidden;
5692         this.totalWidth = null;
5693         this.fireEvent("hiddenchange", this, colIndex, hidden);
5694     },
5695
5696     /**
5697      * Sets the editor for a column.
5698      * @param {Number} col The column index
5699      * @param {Object} editor The editor object
5700      */
5701     setEditor : function(col, editor){
5702         this.config[col].editor = editor;
5703     }
5704 });
5705
5706 Roo.grid.ColumnModel.defaultRenderer = function(value)
5707 {
5708     if(typeof value == "object") {
5709         return value;
5710     }
5711         if(typeof value == "string" && value.length < 1){
5712             return "&#160;";
5713         }
5714     
5715         return String.format("{0}", value);
5716 };
5717
5718 // Alias for backwards compatibility
5719 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5720 /*
5721  * Based on:
5722  * Ext JS Library 1.1.1
5723  * Copyright(c) 2006-2007, Ext JS, LLC.
5724  *
5725  * Originally Released Under LGPL - original licence link has changed is not relivant.
5726  *
5727  * Fork - LGPL
5728  * <script type="text/javascript">
5729  */
5730  
5731 /**
5732  * @class Roo.LoadMask
5733  * A simple utility class for generically masking elements while loading data.  If the element being masked has
5734  * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5735  * process and the mask element will be cached for reuse.  For all other elements, this mask will replace the
5736  * element's UpdateManager load indicator and will be destroyed after the initial load.
5737  * @constructor
5738  * Create a new LoadMask
5739  * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5740  * @param {Object} config The config object
5741  */
5742 Roo.LoadMask = function(el, config){
5743     this.el = Roo.get(el);
5744     Roo.apply(this, config);
5745     if(this.store){
5746         this.store.on('beforeload', this.onBeforeLoad, this);
5747         this.store.on('load', this.onLoad, this);
5748         this.store.on('loadexception', this.onLoadException, this);
5749         this.removeMask = false;
5750     }else{
5751         var um = this.el.getUpdateManager();
5752         um.showLoadIndicator = false; // disable the default indicator
5753         um.on('beforeupdate', this.onBeforeLoad, this);
5754         um.on('update', this.onLoad, this);
5755         um.on('failure', this.onLoad, this);
5756         this.removeMask = true;
5757     }
5758 };
5759
5760 Roo.LoadMask.prototype = {
5761     /**
5762      * @cfg {Boolean} removeMask
5763      * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5764      * False to persist the mask element reference for multiple uses (e.g., for paged data widgets).  Defaults to false.
5765      */
5766     /**
5767      * @cfg {String} msg
5768      * The text to display in a centered loading message box (defaults to 'Loading...')
5769      */
5770     msg : 'Loading...',
5771     /**
5772      * @cfg {String} msgCls
5773      * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5774      */
5775     msgCls : 'x-mask-loading',
5776
5777     /**
5778      * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5779      * @type Boolean
5780      */
5781     disabled: false,
5782
5783     /**
5784      * Disables the mask to prevent it from being displayed
5785      */
5786     disable : function(){
5787        this.disabled = true;
5788     },
5789
5790     /**
5791      * Enables the mask so that it can be displayed
5792      */
5793     enable : function(){
5794         this.disabled = false;
5795     },
5796     
5797     onLoadException : function()
5798     {
5799         Roo.log(arguments);
5800         
5801         if (typeof(arguments[3]) != 'undefined') {
5802             Roo.MessageBox.alert("Error loading",arguments[3]);
5803         } 
5804         /*
5805         try {
5806             if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5807                 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5808             }   
5809         } catch(e) {
5810             
5811         }
5812         */
5813     
5814         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5815     },
5816     // private
5817     onLoad : function()
5818     {
5819         (function() { this.el.unmask(this.removeMask); }).defer(50, this);
5820     },
5821
5822     // private
5823     onBeforeLoad : function(){
5824         if(!this.disabled){
5825             (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
5826         }
5827     },
5828
5829     // private
5830     destroy : function(){
5831         if(this.store){
5832             this.store.un('beforeload', this.onBeforeLoad, this);
5833             this.store.un('load', this.onLoad, this);
5834             this.store.un('loadexception', this.onLoadException, this);
5835         }else{
5836             var um = this.el.getUpdateManager();
5837             um.un('beforeupdate', this.onBeforeLoad, this);
5838             um.un('update', this.onLoad, this);
5839             um.un('failure', this.onLoad, this);
5840         }
5841     }
5842 };/*
5843  * - LGPL
5844  *
5845  * table
5846  * 
5847  */
5848
5849 /**
5850  * @class Roo.bootstrap.Table
5851  * @extends Roo.bootstrap.Component
5852  * Bootstrap Table class
5853  * @cfg {String} cls table class
5854  * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5855  * @cfg {String} bgcolor Specifies the background color for a table
5856  * @cfg {Number} border Specifies whether the table cells should have borders or not
5857  * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5858  * @cfg {Number} cellspacing Specifies the space between cells
5859  * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5860  * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5861  * @cfg {String} sortable Specifies that the table should be sortable
5862  * @cfg {String} summary Specifies a summary of the content of a table
5863  * @cfg {Number} width Specifies the width of a table
5864  * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5865  * 
5866  * @cfg {boolean} striped Should the rows be alternative striped
5867  * @cfg {boolean} bordered Add borders to the table
5868  * @cfg {boolean} hover Add hover highlighting
5869  * @cfg {boolean} condensed Format condensed
5870  * @cfg {boolean} responsive Format condensed
5871  * @cfg {Boolean} loadMask (true|false) default false
5872  * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
5873  * @cfg {Boolean} headerShow (true|false) generate thead, default true
5874  * @cfg {Boolean} rowSelection (true|false) default false
5875  * @cfg {Boolean} cellSelection (true|false) default false
5876  * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
5877  * @cfg {Roo.bootstrap.PagingToolbar} footer  a paging toolbar
5878  * @cfg {Boolean} lazyLoad  auto load data while scrolling to the end (default false)
5879  
5880  * 
5881  * @constructor
5882  * Create a new Table
5883  * @param {Object} config The config object
5884  */
5885
5886 Roo.bootstrap.Table = function(config){
5887     Roo.bootstrap.Table.superclass.constructor.call(this, config);
5888     
5889   
5890     
5891     // BC...
5892     this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
5893     this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
5894     this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
5895     this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
5896     
5897     this.sm = this.sm || {xtype: 'RowSelectionModel'};
5898     if (this.sm) {
5899         this.sm.grid = this;
5900         this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5901         this.sm = this.selModel;
5902         this.sm.xmodule = this.xmodule || false;
5903     }
5904     
5905     if (this.cm && typeof(this.cm.config) == 'undefined') {
5906         this.colModel = new Roo.grid.ColumnModel(this.cm);
5907         this.cm = this.colModel;
5908         this.cm.xmodule = this.xmodule || false;
5909     }
5910     if (this.store) {
5911         this.store= Roo.factory(this.store, Roo.data);
5912         this.ds = this.store;
5913         this.ds.xmodule = this.xmodule || false;
5914          
5915     }
5916     if (this.footer && this.store) {
5917         this.footer.dataSource = this.ds;
5918         this.footer = Roo.factory(this.footer);
5919     }
5920     
5921     /** @private */
5922     this.addEvents({
5923         /**
5924          * @event cellclick
5925          * Fires when a cell is clicked
5926          * @param {Roo.bootstrap.Table} this
5927          * @param {Roo.Element} el
5928          * @param {Number} rowIndex
5929          * @param {Number} columnIndex
5930          * @param {Roo.EventObject} e
5931          */
5932         "cellclick" : true,
5933         /**
5934          * @event celldblclick
5935          * Fires when a cell is double clicked
5936          * @param {Roo.bootstrap.Table} this
5937          * @param {Roo.Element} el
5938          * @param {Number} rowIndex
5939          * @param {Number} columnIndex
5940          * @param {Roo.EventObject} e
5941          */
5942         "celldblclick" : true,
5943         /**
5944          * @event rowclick
5945          * Fires when a row is clicked
5946          * @param {Roo.bootstrap.Table} this
5947          * @param {Roo.Element} el
5948          * @param {Number} rowIndex
5949          * @param {Roo.EventObject} e
5950          */
5951         "rowclick" : true,
5952         /**
5953          * @event rowdblclick
5954          * Fires when a row is double clicked
5955          * @param {Roo.bootstrap.Table} this
5956          * @param {Roo.Element} el
5957          * @param {Number} rowIndex
5958          * @param {Roo.EventObject} e
5959          */
5960         "rowdblclick" : true,
5961         /**
5962          * @event mouseover
5963          * Fires when a mouseover occur
5964          * @param {Roo.bootstrap.Table} this
5965          * @param {Roo.Element} el
5966          * @param {Number} rowIndex
5967          * @param {Number} columnIndex
5968          * @param {Roo.EventObject} e
5969          */
5970         "mouseover" : true,
5971         /**
5972          * @event mouseout
5973          * Fires when a mouseout occur
5974          * @param {Roo.bootstrap.Table} this
5975          * @param {Roo.Element} el
5976          * @param {Number} rowIndex
5977          * @param {Number} columnIndex
5978          * @param {Roo.EventObject} e
5979          */
5980         "mouseout" : true,
5981         /**
5982          * @event rowclass
5983          * Fires when a row is rendered, so you can change add a style to it.
5984          * @param {Roo.bootstrap.Table} this
5985          * @param {Object} rowcfg   contains record  rowIndex colIndex and rowClass - set rowClass to add a style.
5986          */
5987         'rowclass' : true,
5988           /**
5989          * @event rowsrendered
5990          * Fires when all the  rows have been rendered
5991          * @param {Roo.bootstrap.Table} this
5992          */
5993         'rowsrendered' : true,
5994         /**
5995          * @event contextmenu
5996          * The raw contextmenu event for the entire grid.
5997          * @param {Roo.EventObject} e
5998          */
5999         "contextmenu" : true,
6000         /**
6001          * @event rowcontextmenu
6002          * Fires when a row is right clicked
6003          * @param {Roo.bootstrap.Table} this
6004          * @param {Number} rowIndex
6005          * @param {Roo.EventObject} e
6006          */
6007         "rowcontextmenu" : true,
6008         /**
6009          * @event cellcontextmenu
6010          * Fires when a cell is right clicked
6011          * @param {Roo.bootstrap.Table} this
6012          * @param {Number} rowIndex
6013          * @param {Number} cellIndex
6014          * @param {Roo.EventObject} e
6015          */
6016          "cellcontextmenu" : true,
6017          /**
6018          * @event headercontextmenu
6019          * Fires when a header is right clicked
6020          * @param {Roo.bootstrap.Table} this
6021          * @param {Number} columnIndex
6022          * @param {Roo.EventObject} e
6023          */
6024         "headercontextmenu" : true
6025     });
6026 };
6027
6028 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component,  {
6029     
6030     cls: false,
6031     align: false,
6032     bgcolor: false,
6033     border: false,
6034     cellpadding: false,
6035     cellspacing: false,
6036     frame: false,
6037     rules: false,
6038     sortable: false,
6039     summary: false,
6040     width: false,
6041     striped : false,
6042     scrollBody : false,
6043     bordered: false,
6044     hover:  false,
6045     condensed : false,
6046     responsive : false,
6047     sm : false,
6048     cm : false,
6049     store : false,
6050     loadMask : false,
6051     footerShow : true,
6052     headerShow : true,
6053   
6054     rowSelection : false,
6055     cellSelection : false,
6056     layout : false,
6057     
6058     // Roo.Element - the tbody
6059     mainBody: false,
6060     // Roo.Element - thead element
6061     mainHead: false,
6062     
6063     container: false, // used by gridpanel...
6064     
6065     lazyLoad : false,
6066     
6067     CSS : Roo.util.CSS,
6068     
6069     getAutoCreate : function()
6070     {
6071         var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6072         
6073         cfg = {
6074             tag: 'table',
6075             cls : 'table',
6076             cn : []
6077         };
6078         if (this.scrollBody) {
6079             cfg.cls += ' table-body-fixed';
6080         }    
6081         if (this.striped) {
6082             cfg.cls += ' table-striped';
6083         }
6084         
6085         if (this.hover) {
6086             cfg.cls += ' table-hover';
6087         }
6088         if (this.bordered) {
6089             cfg.cls += ' table-bordered';
6090         }
6091         if (this.condensed) {
6092             cfg.cls += ' table-condensed';
6093         }
6094         if (this.responsive) {
6095             cfg.cls += ' table-responsive';
6096         }
6097         
6098         if (this.cls) {
6099             cfg.cls+=  ' ' +this.cls;
6100         }
6101         
6102         // this lot should be simplifed...
6103         
6104         if (this.align) {
6105             cfg.align=this.align;
6106         }
6107         if (this.bgcolor) {
6108             cfg.bgcolor=this.bgcolor;
6109         }
6110         if (this.border) {
6111             cfg.border=this.border;
6112         }
6113         if (this.cellpadding) {
6114             cfg.cellpadding=this.cellpadding;
6115         }
6116         if (this.cellspacing) {
6117             cfg.cellspacing=this.cellspacing;
6118         }
6119         if (this.frame) {
6120             cfg.frame=this.frame;
6121         }
6122         if (this.rules) {
6123             cfg.rules=this.rules;
6124         }
6125         if (this.sortable) {
6126             cfg.sortable=this.sortable;
6127         }
6128         if (this.summary) {
6129             cfg.summary=this.summary;
6130         }
6131         if (this.width) {
6132             cfg.width=this.width;
6133         }
6134         if (this.layout) {
6135             cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6136         }
6137         
6138         if(this.store || this.cm){
6139             if(this.headerShow){
6140                 cfg.cn.push(this.renderHeader());
6141             }
6142             
6143             cfg.cn.push(this.renderBody());
6144             
6145             if(this.footerShow){
6146                 cfg.cn.push(this.renderFooter());
6147             }
6148             // where does this come from?
6149             //cfg.cls+=  ' TableGrid';
6150         }
6151         
6152         return { cn : [ cfg ] };
6153     },
6154     
6155     initEvents : function()
6156     {   
6157         if(!this.store || !this.cm){
6158             return;
6159         }
6160         if (this.selModel) {
6161             this.selModel.initEvents();
6162         }
6163         
6164         
6165         //Roo.log('initEvents with ds!!!!');
6166         
6167         this.mainBody = this.el.select('tbody', true).first();
6168         this.mainHead = this.el.select('thead', true).first();
6169         
6170         
6171         
6172         
6173         var _this = this;
6174         
6175         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6176             e.on('click', _this.sort, _this);
6177         });
6178         
6179         this.mainBody.on("click", this.onClick, this);
6180         this.mainBody.on("dblclick", this.onDblClick, this);
6181         
6182         // why is this done????? = it breaks dialogs??
6183         //this.parent().el.setStyle('position', 'relative');
6184         
6185         
6186         if (this.footer) {
6187             this.footer.parentId = this.id;
6188             this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6189             
6190             if(this.lazyLoad){
6191                 this.el.select('tfoot tr td').first().addClass('hide');
6192             }
6193         } 
6194         
6195         if(this.loadMask) {
6196             this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6197         }
6198         
6199         this.store.on('load', this.onLoad, this);
6200         this.store.on('beforeload', this.onBeforeLoad, this);
6201         this.store.on('update', this.onUpdate, this);
6202         this.store.on('add', this.onAdd, this);
6203         this.store.on("clear", this.clear, this);
6204         
6205         this.el.on("contextmenu", this.onContextMenu, this);
6206         
6207         this.mainBody.on('scroll', this.onBodyScroll, this);
6208         
6209         this.cm.on("headerchange", this.onHeaderChange, this);
6210         
6211         this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6212         
6213     },
6214     
6215     onContextMenu : function(e, t)
6216     {
6217         this.processEvent("contextmenu", e);
6218     },
6219     
6220     processEvent : function(name, e)
6221     {
6222         if (name != 'touchstart' ) {
6223             this.fireEvent(name, e);    
6224         }
6225         
6226         var t = e.getTarget();
6227         
6228         var cell = Roo.get(t);
6229         
6230         if(!cell){
6231             return;
6232         }
6233         
6234         if(cell.findParent('tfoot', false, true)){
6235             return;
6236         }
6237         
6238         if(cell.findParent('thead', false, true)){
6239             
6240             if(e.getTarget().nodeName.toLowerCase() != 'th'){
6241                 cell = Roo.get(t).findParent('th', false, true);
6242                 if (!cell) {
6243                     Roo.log("failed to find th in thead?");
6244                     Roo.log(e.getTarget());
6245                     return;
6246                 }
6247             }
6248             
6249             var cellIndex = cell.dom.cellIndex;
6250             
6251             var ename = name == 'touchstart' ? 'click' : name;
6252             this.fireEvent("header" + ename, this, cellIndex, e);
6253             
6254             return;
6255         }
6256         
6257         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6258             cell = Roo.get(t).findParent('td', false, true);
6259             if (!cell) {
6260                 Roo.log("failed to find th in tbody?");
6261                 Roo.log(e.getTarget());
6262                 return;
6263             }
6264         }
6265         
6266         var row = cell.findParent('tr', false, true);
6267         var cellIndex = cell.dom.cellIndex;
6268         var rowIndex = row.dom.rowIndex - 1;
6269         
6270         if(row !== false){
6271             
6272             this.fireEvent("row" + name, this, rowIndex, e);
6273             
6274             if(cell !== false){
6275             
6276                 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6277             }
6278         }
6279         
6280     },
6281     
6282     onMouseover : function(e, el)
6283     {
6284         var cell = Roo.get(el);
6285         
6286         if(!cell){
6287             return;
6288         }
6289         
6290         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6291             cell = cell.findParent('td', false, true);
6292         }
6293         
6294         var row = cell.findParent('tr', false, true);
6295         var cellIndex = cell.dom.cellIndex;
6296         var rowIndex = row.dom.rowIndex - 1; // start from 0
6297         
6298         this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6299         
6300     },
6301     
6302     onMouseout : function(e, el)
6303     {
6304         var cell = Roo.get(el);
6305         
6306         if(!cell){
6307             return;
6308         }
6309         
6310         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6311             cell = cell.findParent('td', false, true);
6312         }
6313         
6314         var row = cell.findParent('tr', false, true);
6315         var cellIndex = cell.dom.cellIndex;
6316         var rowIndex = row.dom.rowIndex - 1; // start from 0
6317         
6318         this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6319         
6320     },
6321     
6322     onClick : function(e, el)
6323     {
6324         var cell = Roo.get(el);
6325         
6326         if(!cell || (!this.cellSelection && !this.rowSelection)){
6327             return;
6328         }
6329         
6330         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6331             cell = cell.findParent('td', false, true);
6332         }
6333         
6334         if(!cell || typeof(cell) == 'undefined'){
6335             return;
6336         }
6337         
6338         var row = cell.findParent('tr', false, true);
6339         
6340         if(!row || typeof(row) == 'undefined'){
6341             return;
6342         }
6343         
6344         var cellIndex = cell.dom.cellIndex;
6345         var rowIndex = this.getRowIndex(row);
6346         
6347         // why??? - should these not be based on SelectionModel?
6348         if(this.cellSelection){
6349             this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6350         }
6351         
6352         if(this.rowSelection){
6353             this.fireEvent('rowclick', this, row, rowIndex, e);
6354         }
6355         
6356         
6357     },
6358         
6359     onDblClick : function(e,el)
6360     {
6361         var cell = Roo.get(el);
6362         
6363         if(!cell || (!this.cellSelection && !this.rowSelection)){
6364             return;
6365         }
6366         
6367         if(e.getTarget().nodeName.toLowerCase() != 'td'){
6368             cell = cell.findParent('td', false, true);
6369         }
6370         
6371         if(!cell || typeof(cell) == 'undefined'){
6372             return;
6373         }
6374         
6375         var row = cell.findParent('tr', false, true);
6376         
6377         if(!row || typeof(row) == 'undefined'){
6378             return;
6379         }
6380         
6381         var cellIndex = cell.dom.cellIndex;
6382         var rowIndex = this.getRowIndex(row);
6383         
6384         if(this.cellSelection){
6385             this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6386         }
6387         
6388         if(this.rowSelection){
6389             this.fireEvent('rowdblclick', this, row, rowIndex, e);
6390         }
6391     },
6392     
6393     sort : function(e,el)
6394     {
6395         var col = Roo.get(el);
6396         
6397         if(!col.hasClass('sortable')){
6398             return;
6399         }
6400         
6401         var sort = col.attr('sort');
6402         var dir = 'ASC';
6403         
6404         if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6405             dir = 'DESC';
6406         }
6407         
6408         this.store.sortInfo = {field : sort, direction : dir};
6409         
6410         if (this.footer) {
6411             Roo.log("calling footer first");
6412             this.footer.onClick('first');
6413         } else {
6414         
6415             this.store.load({ params : { start : 0 } });
6416         }
6417     },
6418     
6419     renderHeader : function()
6420     {
6421         var header = {
6422             tag: 'thead',
6423             cn : []
6424         };
6425         
6426         var cm = this.cm;
6427         this.totalWidth = 0;
6428         
6429         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6430             
6431             var config = cm.config[i];
6432             
6433             var c = {
6434                 tag: 'th',
6435                 cls : 'x-hcol-' + i,
6436                 style : '',
6437                 html: cm.getColumnHeader(i)
6438             };
6439             
6440             var hh = '';
6441             
6442             if(typeof(config.sortable) != 'undefined' && config.sortable){
6443                 c.cls = 'sortable';
6444                 c.html = '<i class="glyphicon"></i>' + c.html;
6445             }
6446             
6447             if(typeof(config.lgHeader) != 'undefined'){
6448                 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6449             }
6450             
6451             if(typeof(config.mdHeader) != 'undefined'){
6452                 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6453             }
6454             
6455             if(typeof(config.smHeader) != 'undefined'){
6456                 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6457             }
6458             
6459             if(typeof(config.xsHeader) != 'undefined'){
6460                 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6461             }
6462             
6463             if(hh.length){
6464                 c.html = hh;
6465             }
6466             
6467             if(typeof(config.tooltip) != 'undefined'){
6468                 c.tooltip = config.tooltip;
6469             }
6470             
6471             if(typeof(config.colspan) != 'undefined'){
6472                 c.colspan = config.colspan;
6473             }
6474             
6475             if(typeof(config.hidden) != 'undefined' && config.hidden){
6476                 c.style += ' display:none;';
6477             }
6478             
6479             if(typeof(config.dataIndex) != 'undefined'){
6480                 c.sort = config.dataIndex;
6481             }
6482             
6483            
6484             
6485             if(typeof(config.align) != 'undefined' && config.align.length){
6486                 c.style += ' text-align:' + config.align + ';';
6487             }
6488             
6489             if(typeof(config.width) != 'undefined'){
6490                 c.style += ' width:' + config.width + 'px;';
6491                 this.totalWidth += config.width;
6492             } else {
6493                 this.totalWidth += 100; // assume minimum of 100 per column?
6494             }
6495             
6496             if(typeof(config.cls) != 'undefined'){
6497                 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6498             }
6499             
6500             ['xs','sm','md','lg'].map(function(size){
6501                 
6502                 if(typeof(config[size]) == 'undefined'){
6503                     return;
6504                 }
6505                 
6506                 if (!config[size]) { // 0 = hidden
6507                     c.cls += ' hidden-' + size;
6508                     return;
6509                 }
6510                 
6511                 c.cls += ' col-' + size + '-' + config[size];
6512
6513             });
6514             
6515             header.cn.push(c)
6516         }
6517         
6518         return header;
6519     },
6520     
6521     renderBody : function()
6522     {
6523         var body = {
6524             tag: 'tbody',
6525             cn : [
6526                 {
6527                     tag: 'tr',
6528                     cn : [
6529                         {
6530                             tag : 'td',
6531                             colspan :  this.cm.getColumnCount()
6532                         }
6533                     ]
6534                 }
6535             ]
6536         };
6537         
6538         return body;
6539     },
6540     
6541     renderFooter : function()
6542     {
6543         var footer = {
6544             tag: 'tfoot',
6545             cn : [
6546                 {
6547                     tag: 'tr',
6548                     cn : [
6549                         {
6550                             tag : 'td',
6551                             colspan :  this.cm.getColumnCount()
6552                         }
6553                     ]
6554                 }
6555             ]
6556         };
6557         
6558         return footer;
6559     },
6560     
6561     
6562     
6563     onLoad : function()
6564     {
6565 //        Roo.log('ds onload');
6566         this.clear();
6567         
6568         var _this = this;
6569         var cm = this.cm;
6570         var ds = this.store;
6571         
6572         Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6573             e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6574             if (_this.store.sortInfo) {
6575                     
6576                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6577                     e.select('i', true).addClass(['glyphicon-arrow-up']);
6578                 }
6579                 
6580                 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6581                     e.select('i', true).addClass(['glyphicon-arrow-down']);
6582                 }
6583             }
6584         });
6585         
6586         var tbody =  this.mainBody;
6587               
6588         if(ds.getCount() > 0){
6589             ds.data.each(function(d,rowIndex){
6590                 var row =  this.renderRow(cm, ds, rowIndex);
6591                 
6592                 tbody.createChild(row);
6593                 
6594                 var _this = this;
6595                 
6596                 if(row.cellObjects.length){
6597                     Roo.each(row.cellObjects, function(r){
6598                         _this.renderCellObject(r);
6599                     })
6600                 }
6601                 
6602             }, this);
6603         }
6604         
6605         Roo.each(this.el.select('tbody td', true).elements, function(e){
6606             e.on('mouseover', _this.onMouseover, _this);
6607         });
6608         
6609         Roo.each(this.el.select('tbody td', true).elements, function(e){
6610             e.on('mouseout', _this.onMouseout, _this);
6611         });
6612         this.fireEvent('rowsrendered', this);
6613         
6614         this.autoSize();
6615     },
6616     
6617     
6618     onUpdate : function(ds,record)
6619     {
6620         this.refreshRow(record);
6621         this.autoSize();
6622     },
6623     
6624     onRemove : function(ds, record, index, isUpdate){
6625         if(isUpdate !== true){
6626             this.fireEvent("beforerowremoved", this, index, record);
6627         }
6628         var bt = this.mainBody.dom;
6629         
6630         var rows = this.el.select('tbody > tr', true).elements;
6631         
6632         if(typeof(rows[index]) != 'undefined'){
6633             bt.removeChild(rows[index].dom);
6634         }
6635         
6636 //        if(bt.rows[index]){
6637 //            bt.removeChild(bt.rows[index]);
6638 //        }
6639         
6640         if(isUpdate !== true){
6641             //this.stripeRows(index);
6642             //this.syncRowHeights(index, index);
6643             //this.layout();
6644             this.fireEvent("rowremoved", this, index, record);
6645         }
6646     },
6647     
6648     onAdd : function(ds, records, rowIndex)
6649     {
6650         //Roo.log('on Add called');
6651         // - note this does not handle multiple adding very well..
6652         var bt = this.mainBody.dom;
6653         for (var i =0 ; i < records.length;i++) {
6654             //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6655             //Roo.log(records[i]);
6656             //Roo.log(this.store.getAt(rowIndex+i));
6657             this.insertRow(this.store, rowIndex + i, false);
6658             return;
6659         }
6660         
6661     },
6662     
6663     
6664     refreshRow : function(record){
6665         var ds = this.store, index;
6666         if(typeof record == 'number'){
6667             index = record;
6668             record = ds.getAt(index);
6669         }else{
6670             index = ds.indexOf(record);
6671         }
6672         this.insertRow(ds, index, true);
6673         this.autoSize();
6674         this.onRemove(ds, record, index+1, true);
6675         this.autoSize();
6676         //this.syncRowHeights(index, index);
6677         //this.layout();
6678         this.fireEvent("rowupdated", this, index, record);
6679     },
6680     
6681     insertRow : function(dm, rowIndex, isUpdate){
6682         
6683         if(!isUpdate){
6684             this.fireEvent("beforerowsinserted", this, rowIndex);
6685         }
6686             //var s = this.getScrollState();
6687         var row = this.renderRow(this.cm, this.store, rowIndex);
6688         // insert before rowIndex..
6689         var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6690         
6691         var _this = this;
6692                 
6693         if(row.cellObjects.length){
6694             Roo.each(row.cellObjects, function(r){
6695                 _this.renderCellObject(r);
6696             })
6697         }
6698             
6699         if(!isUpdate){
6700             this.fireEvent("rowsinserted", this, rowIndex);
6701             //this.syncRowHeights(firstRow, lastRow);
6702             //this.stripeRows(firstRow);
6703             //this.layout();
6704         }
6705         
6706     },
6707     
6708     
6709     getRowDom : function(rowIndex)
6710     {
6711         var rows = this.el.select('tbody > tr', true).elements;
6712         
6713         return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6714         
6715     },
6716     // returns the object tree for a tr..
6717   
6718     
6719     renderRow : function(cm, ds, rowIndex) 
6720     {
6721         var d = ds.getAt(rowIndex);
6722         
6723         var row = {
6724             tag : 'tr',
6725             cls : 'x-row-' + rowIndex,
6726             cn : []
6727         };
6728             
6729         var cellObjects = [];
6730         
6731         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6732             var config = cm.config[i];
6733             
6734             var renderer = cm.getRenderer(i);
6735             var value = '';
6736             var id = false;
6737             
6738             if(typeof(renderer) !== 'undefined'){
6739                 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6740             }
6741             // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6742             // and are rendered into the cells after the row is rendered - using the id for the element.
6743             
6744             if(typeof(value) === 'object'){
6745                 id = Roo.id();
6746                 cellObjects.push({
6747                     container : id,
6748                     cfg : value 
6749                 })
6750             }
6751             
6752             var rowcfg = {
6753                 record: d,
6754                 rowIndex : rowIndex,
6755                 colIndex : i,
6756                 rowClass : ''
6757             };
6758
6759             this.fireEvent('rowclass', this, rowcfg);
6760             
6761             var td = {
6762                 tag: 'td',
6763                 cls : rowcfg.rowClass + ' x-col-' + i,
6764                 style: '',
6765                 html: (typeof(value) === 'object') ? '' : value
6766             };
6767             
6768             if (id) {
6769                 td.id = id;
6770             }
6771             
6772             if(typeof(config.colspan) != 'undefined'){
6773                 td.colspan = config.colspan;
6774             }
6775             
6776             if(typeof(config.hidden) != 'undefined' && config.hidden){
6777                 td.style += ' display:none;';
6778             }
6779             
6780             if(typeof(config.align) != 'undefined' && config.align.length){
6781                 td.style += ' text-align:' + config.align + ';';
6782             }
6783             
6784             if(typeof(config.width) != 'undefined'){
6785                 td.style += ' width:' +  config.width + 'px;';
6786             }
6787             
6788             if(typeof(config.cursor) != 'undefined'){
6789                 td.style += ' cursor:' +  config.cursor + ';';
6790             }
6791             
6792             if(typeof(config.cls) != 'undefined'){
6793                 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6794             }
6795             
6796             ['xs','sm','md','lg'].map(function(size){
6797                 
6798                 if(typeof(config[size]) == 'undefined'){
6799                     return;
6800                 }
6801                 
6802                 if (!config[size]) { // 0 = hidden
6803                     td.cls += ' hidden-' + size;
6804                     return;
6805                 }
6806                 
6807                 td.cls += ' col-' + size + '-' + config[size];
6808
6809             });
6810             
6811             row.cn.push(td);
6812            
6813         }
6814         
6815         row.cellObjects = cellObjects;
6816         
6817         return row;
6818           
6819     },
6820     
6821     
6822     
6823     onBeforeLoad : function()
6824     {
6825         
6826     },
6827      /**
6828      * Remove all rows
6829      */
6830     clear : function()
6831     {
6832         this.el.select('tbody', true).first().dom.innerHTML = '';
6833     },
6834     /**
6835      * Show or hide a row.
6836      * @param {Number} rowIndex to show or hide
6837      * @param {Boolean} state hide
6838      */
6839     setRowVisibility : function(rowIndex, state)
6840     {
6841         var bt = this.mainBody.dom;
6842         
6843         var rows = this.el.select('tbody > tr', true).elements;
6844         
6845         if(typeof(rows[rowIndex]) == 'undefined'){
6846             return;
6847         }
6848         rows[rowIndex].dom.style.display = state ? '' : 'none';
6849     },
6850     
6851     
6852     getSelectionModel : function(){
6853         if(!this.selModel){
6854             this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
6855         }
6856         return this.selModel;
6857     },
6858     /*
6859      * Render the Roo.bootstrap object from renderder
6860      */
6861     renderCellObject : function(r)
6862     {
6863         var _this = this;
6864         
6865         r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
6866         
6867         var t = r.cfg.render(r.container);
6868         
6869         if(r.cfg.cn){
6870             Roo.each(r.cfg.cn, function(c){
6871                 var child = {
6872                     container: t.getChildContainer(),
6873                     cfg: c
6874                 };
6875                 _this.renderCellObject(child);
6876             })
6877         }
6878     },
6879     
6880     getRowIndex : function(row)
6881     {
6882         var rowIndex = -1;
6883         
6884         Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6885             if(el != row){
6886                 return;
6887             }
6888             
6889             rowIndex = index;
6890         });
6891         
6892         return rowIndex;
6893     },
6894      /**
6895      * Returns the grid's underlying element = used by panel.Grid
6896      * @return {Element} The element
6897      */
6898     getGridEl : function(){
6899         return this.el;
6900     },
6901      /**
6902      * Forces a resize - used by panel.Grid
6903      * @return {Element} The element
6904      */
6905     autoSize : function()
6906     {
6907         //var ctr = Roo.get(this.container.dom.parentElement);
6908         var ctr = Roo.get(this.el.dom);
6909         
6910         var thd = this.getGridEl().select('thead',true).first();
6911         var tbd = this.getGridEl().select('tbody', true).first();
6912         var tfd = this.getGridEl().select('tfoot', true).first();
6913         
6914         var cw = ctr.getWidth();
6915         
6916         if (tbd) {
6917             
6918             tbd.setSize(ctr.getWidth(),
6919                         ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
6920             );
6921             var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
6922             cw -= barsize;
6923         }
6924         cw = Math.max(cw, this.totalWidth);
6925         this.getGridEl().select('tr',true).setWidth(cw);
6926         // resize 'expandable coloumn?
6927         
6928         return; // we doe not have a view in this design..
6929         
6930     },
6931     onBodyScroll: function()
6932     {
6933         //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
6934         if(this.mainHead){
6935             this.mainHead.setStyle({
6936                 'position' : 'relative',
6937                 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
6938             });
6939         }
6940         
6941         if(this.lazyLoad){
6942             
6943             var scrollHeight = this.mainBody.dom.scrollHeight;
6944             
6945             var scrollTop = Math.ceil(this.mainBody.getScroll().top);
6946             
6947             var height = this.mainBody.getHeight();
6948             
6949             if(scrollHeight - height == scrollTop) {
6950                 
6951                 var total = this.ds.getTotalCount();
6952                 
6953                 if(this.footer.cursor + this.footer.pageSize < total){
6954                     
6955                     this.footer.ds.load({
6956                         params : {
6957                             start : this.footer.cursor + this.footer.pageSize,
6958                             limit : this.footer.pageSize
6959                         },
6960                         add : true
6961                     });
6962                 }
6963             }
6964             
6965         }
6966     },
6967     
6968     onHeaderChange : function()
6969     {
6970         var header = this.renderHeader();
6971         var table = this.el.select('table', true).first();
6972         
6973         this.mainHead.remove();
6974         this.mainHead = table.createChild(header, this.mainBody, false);
6975     },
6976     
6977     onHiddenChange : function(colModel, colIndex, hidden)
6978     {
6979         var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
6980         var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
6981         
6982         this.CSS.updateRule(thSelector, "display", "");
6983         this.CSS.updateRule(tdSelector, "display", "");
6984         
6985         if(hidden){
6986             this.CSS.updateRule(thSelector, "display", "none");
6987             this.CSS.updateRule(tdSelector, "display", "none");
6988         }
6989         
6990         this.onHeaderChange();
6991         this.onLoad();
6992         
6993     }
6994     
6995 });
6996
6997  
6998
6999  /*
7000  * - LGPL
7001  *
7002  * table cell
7003  * 
7004  */
7005
7006 /**
7007  * @class Roo.bootstrap.TableCell
7008  * @extends Roo.bootstrap.Component
7009  * Bootstrap TableCell class
7010  * @cfg {String} html cell contain text
7011  * @cfg {String} cls cell class
7012  * @cfg {String} tag cell tag (td|th) default td
7013  * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7014  * @cfg {String} align Aligns the content in a cell
7015  * @cfg {String} axis Categorizes cells
7016  * @cfg {String} bgcolor Specifies the background color of a cell
7017  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7018  * @cfg {Number} colspan Specifies the number of columns a cell should span
7019  * @cfg {String} headers Specifies one or more header cells a cell is related to
7020  * @cfg {Number} height Sets the height of a cell
7021  * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7022  * @cfg {Number} rowspan Sets the number of rows a cell should span
7023  * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7024  * @cfg {String} valign Vertical aligns the content in a cell
7025  * @cfg {Number} width Specifies the width of a cell
7026  * 
7027  * @constructor
7028  * Create a new TableCell
7029  * @param {Object} config The config object
7030  */
7031
7032 Roo.bootstrap.TableCell = function(config){
7033     Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7034 };
7035
7036 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component,  {
7037     
7038     html: false,
7039     cls: false,
7040     tag: false,
7041     abbr: false,
7042     align: false,
7043     axis: false,
7044     bgcolor: false,
7045     charoff: false,
7046     colspan: false,
7047     headers: false,
7048     height: false,
7049     nowrap: false,
7050     rowspan: false,
7051     scope: false,
7052     valign: false,
7053     width: false,
7054     
7055     
7056     getAutoCreate : function(){
7057         var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7058         
7059         cfg = {
7060             tag: 'td'
7061         };
7062         
7063         if(this.tag){
7064             cfg.tag = this.tag;
7065         }
7066         
7067         if (this.html) {
7068             cfg.html=this.html
7069         }
7070         if (this.cls) {
7071             cfg.cls=this.cls
7072         }
7073         if (this.abbr) {
7074             cfg.abbr=this.abbr
7075         }
7076         if (this.align) {
7077             cfg.align=this.align
7078         }
7079         if (this.axis) {
7080             cfg.axis=this.axis
7081         }
7082         if (this.bgcolor) {
7083             cfg.bgcolor=this.bgcolor
7084         }
7085         if (this.charoff) {
7086             cfg.charoff=this.charoff
7087         }
7088         if (this.colspan) {
7089             cfg.colspan=this.colspan
7090         }
7091         if (this.headers) {
7092             cfg.headers=this.headers
7093         }
7094         if (this.height) {
7095             cfg.height=this.height
7096         }
7097         if (this.nowrap) {
7098             cfg.nowrap=this.nowrap
7099         }
7100         if (this.rowspan) {
7101             cfg.rowspan=this.rowspan
7102         }
7103         if (this.scope) {
7104             cfg.scope=this.scope
7105         }
7106         if (this.valign) {
7107             cfg.valign=this.valign
7108         }
7109         if (this.width) {
7110             cfg.width=this.width
7111         }
7112         
7113         
7114         return cfg;
7115     }
7116    
7117 });
7118
7119  
7120
7121  /*
7122  * - LGPL
7123  *
7124  * table row
7125  * 
7126  */
7127
7128 /**
7129  * @class Roo.bootstrap.TableRow
7130  * @extends Roo.bootstrap.Component
7131  * Bootstrap TableRow class
7132  * @cfg {String} cls row class
7133  * @cfg {String} align Aligns the content in a table row
7134  * @cfg {String} bgcolor Specifies a background color for a table row
7135  * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7136  * @cfg {String} valign Vertical aligns the content in a table row
7137  * 
7138  * @constructor
7139  * Create a new TableRow
7140  * @param {Object} config The config object
7141  */
7142
7143 Roo.bootstrap.TableRow = function(config){
7144     Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7145 };
7146
7147 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component,  {
7148     
7149     cls: false,
7150     align: false,
7151     bgcolor: false,
7152     charoff: false,
7153     valign: false,
7154     
7155     getAutoCreate : function(){
7156         var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7157         
7158         cfg = {
7159             tag: 'tr'
7160         };
7161             
7162         if(this.cls){
7163             cfg.cls = this.cls;
7164         }
7165         if(this.align){
7166             cfg.align = this.align;
7167         }
7168         if(this.bgcolor){
7169             cfg.bgcolor = this.bgcolor;
7170         }
7171         if(this.charoff){
7172             cfg.charoff = this.charoff;
7173         }
7174         if(this.valign){
7175             cfg.valign = this.valign;
7176         }
7177         
7178         return cfg;
7179     }
7180    
7181 });
7182
7183  
7184
7185  /*
7186  * - LGPL
7187  *
7188  * table body
7189  * 
7190  */
7191
7192 /**
7193  * @class Roo.bootstrap.TableBody
7194  * @extends Roo.bootstrap.Component
7195  * Bootstrap TableBody class
7196  * @cfg {String} cls element class
7197  * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7198  * @cfg {String} align Aligns the content inside the element
7199  * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7200  * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7201  * 
7202  * @constructor
7203  * Create a new TableBody
7204  * @param {Object} config The config object
7205  */
7206
7207 Roo.bootstrap.TableBody = function(config){
7208     Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7209 };
7210
7211 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component,  {
7212     
7213     cls: false,
7214     tag: false,
7215     align: false,
7216     charoff: false,
7217     valign: false,
7218     
7219     getAutoCreate : function(){
7220         var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7221         
7222         cfg = {
7223             tag: 'tbody'
7224         };
7225             
7226         if (this.cls) {
7227             cfg.cls=this.cls
7228         }
7229         if(this.tag){
7230             cfg.tag = this.tag;
7231         }
7232         
7233         if(this.align){
7234             cfg.align = this.align;
7235         }
7236         if(this.charoff){
7237             cfg.charoff = this.charoff;
7238         }
7239         if(this.valign){
7240             cfg.valign = this.valign;
7241         }
7242         
7243         return cfg;
7244     }
7245     
7246     
7247 //    initEvents : function()
7248 //    {
7249 //        
7250 //        if(!this.store){
7251 //            return;
7252 //        }
7253 //        
7254 //        this.store = Roo.factory(this.store, Roo.data);
7255 //        this.store.on('load', this.onLoad, this);
7256 //        
7257 //        this.store.load();
7258 //        
7259 //    },
7260 //    
7261 //    onLoad: function () 
7262 //    {   
7263 //        this.fireEvent('load', this);
7264 //    }
7265 //    
7266 //   
7267 });
7268
7269  
7270
7271  /*
7272  * Based on:
7273  * Ext JS Library 1.1.1
7274  * Copyright(c) 2006-2007, Ext JS, LLC.
7275  *
7276  * Originally Released Under LGPL - original licence link has changed is not relivant.
7277  *
7278  * Fork - LGPL
7279  * <script type="text/javascript">
7280  */
7281
7282 // as we use this in bootstrap.
7283 Roo.namespace('Roo.form');
7284  /**
7285  * @class Roo.form.Action
7286  * Internal Class used to handle form actions
7287  * @constructor
7288  * @param {Roo.form.BasicForm} el The form element or its id
7289  * @param {Object} config Configuration options
7290  */
7291
7292  
7293  
7294 // define the action interface
7295 Roo.form.Action = function(form, options){
7296     this.form = form;
7297     this.options = options || {};
7298 };
7299 /**
7300  * Client Validation Failed
7301  * @const 
7302  */
7303 Roo.form.Action.CLIENT_INVALID = 'client';
7304 /**
7305  * Server Validation Failed
7306  * @const 
7307  */
7308 Roo.form.Action.SERVER_INVALID = 'server';
7309  /**
7310  * Connect to Server Failed
7311  * @const 
7312  */
7313 Roo.form.Action.CONNECT_FAILURE = 'connect';
7314 /**
7315  * Reading Data from Server Failed
7316  * @const 
7317  */
7318 Roo.form.Action.LOAD_FAILURE = 'load';
7319
7320 Roo.form.Action.prototype = {
7321     type : 'default',
7322     failureType : undefined,
7323     response : undefined,
7324     result : undefined,
7325
7326     // interface method
7327     run : function(options){
7328
7329     },
7330
7331     // interface method
7332     success : function(response){
7333
7334     },
7335
7336     // interface method
7337     handleResponse : function(response){
7338
7339     },
7340
7341     // default connection failure
7342     failure : function(response){
7343         
7344         this.response = response;
7345         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7346         this.form.afterAction(this, false);
7347     },
7348
7349     processResponse : function(response){
7350         this.response = response;
7351         if(!response.responseText){
7352             return true;
7353         }
7354         this.result = this.handleResponse(response);
7355         return this.result;
7356     },
7357
7358     // utility functions used internally
7359     getUrl : function(appendParams){
7360         var url = this.options.url || this.form.url || this.form.el.dom.action;
7361         if(appendParams){
7362             var p = this.getParams();
7363             if(p){
7364                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7365             }
7366         }
7367         return url;
7368     },
7369
7370     getMethod : function(){
7371         return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7372     },
7373
7374     getParams : function(){
7375         var bp = this.form.baseParams;
7376         var p = this.options.params;
7377         if(p){
7378             if(typeof p == "object"){
7379                 p = Roo.urlEncode(Roo.applyIf(p, bp));
7380             }else if(typeof p == 'string' && bp){
7381                 p += '&' + Roo.urlEncode(bp);
7382             }
7383         }else if(bp){
7384             p = Roo.urlEncode(bp);
7385         }
7386         return p;
7387     },
7388
7389     createCallback : function(){
7390         return {
7391             success: this.success,
7392             failure: this.failure,
7393             scope: this,
7394             timeout: (this.form.timeout*1000),
7395             upload: this.form.fileUpload ? this.success : undefined
7396         };
7397     }
7398 };
7399
7400 Roo.form.Action.Submit = function(form, options){
7401     Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7402 };
7403
7404 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7405     type : 'submit',
7406
7407     haveProgress : false,
7408     uploadComplete : false,
7409     
7410     // uploadProgress indicator.
7411     uploadProgress : function()
7412     {
7413         if (!this.form.progressUrl) {
7414             return;
7415         }
7416         
7417         if (!this.haveProgress) {
7418             Roo.MessageBox.progress("Uploading", "Uploading");
7419         }
7420         if (this.uploadComplete) {
7421            Roo.MessageBox.hide();
7422            return;
7423         }
7424         
7425         this.haveProgress = true;
7426    
7427         var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7428         
7429         var c = new Roo.data.Connection();
7430         c.request({
7431             url : this.form.progressUrl,
7432             params: {
7433                 id : uid
7434             },
7435             method: 'GET',
7436             success : function(req){
7437                //console.log(data);
7438                 var rdata = false;
7439                 var edata;
7440                 try  {
7441                    rdata = Roo.decode(req.responseText)
7442                 } catch (e) {
7443                     Roo.log("Invalid data from server..");
7444                     Roo.log(edata);
7445                     return;
7446                 }
7447                 if (!rdata || !rdata.success) {
7448                     Roo.log(rdata);
7449                     Roo.MessageBox.alert(Roo.encode(rdata));
7450                     return;
7451                 }
7452                 var data = rdata.data;
7453                 
7454                 if (this.uploadComplete) {
7455                    Roo.MessageBox.hide();
7456                    return;
7457                 }
7458                    
7459                 if (data){
7460                     Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7461                        Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7462                     );
7463                 }
7464                 this.uploadProgress.defer(2000,this);
7465             },
7466        
7467             failure: function(data) {
7468                 Roo.log('progress url failed ');
7469                 Roo.log(data);
7470             },
7471             scope : this
7472         });
7473            
7474     },
7475     
7476     
7477     run : function()
7478     {
7479         // run get Values on the form, so it syncs any secondary forms.
7480         this.form.getValues();
7481         
7482         var o = this.options;
7483         var method = this.getMethod();
7484         var isPost = method == 'POST';
7485         if(o.clientValidation === false || this.form.isValid()){
7486             
7487             if (this.form.progressUrl) {
7488                 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7489                     (new Date() * 1) + '' + Math.random());
7490                     
7491             } 
7492             
7493             
7494             Roo.Ajax.request(Roo.apply(this.createCallback(), {
7495                 form:this.form.el.dom,
7496                 url:this.getUrl(!isPost),
7497                 method: method,
7498                 params:isPost ? this.getParams() : null,
7499                 isUpload: this.form.fileUpload
7500             }));
7501             
7502             this.uploadProgress();
7503
7504         }else if (o.clientValidation !== false){ // client validation failed
7505             this.failureType = Roo.form.Action.CLIENT_INVALID;
7506             this.form.afterAction(this, false);
7507         }
7508     },
7509
7510     success : function(response)
7511     {
7512         this.uploadComplete= true;
7513         if (this.haveProgress) {
7514             Roo.MessageBox.hide();
7515         }
7516         
7517         
7518         var result = this.processResponse(response);
7519         if(result === true || result.success){
7520             this.form.afterAction(this, true);
7521             return;
7522         }
7523         if(result.errors){
7524             this.form.markInvalid(result.errors);
7525             this.failureType = Roo.form.Action.SERVER_INVALID;
7526         }
7527         this.form.afterAction(this, false);
7528     },
7529     failure : function(response)
7530     {
7531         this.uploadComplete= true;
7532         if (this.haveProgress) {
7533             Roo.MessageBox.hide();
7534         }
7535         
7536         this.response = response;
7537         this.failureType = Roo.form.Action.CONNECT_FAILURE;
7538         this.form.afterAction(this, false);
7539     },
7540     
7541     handleResponse : function(response){
7542         if(this.form.errorReader){
7543             var rs = this.form.errorReader.read(response);
7544             var errors = [];
7545             if(rs.records){
7546                 for(var i = 0, len = rs.records.length; i < len; i++) {
7547                     var r = rs.records[i];
7548                     errors[i] = r.data;
7549                 }
7550             }
7551             if(errors.length < 1){
7552                 errors = null;
7553             }
7554             return {
7555                 success : rs.success,
7556                 errors : errors
7557             };
7558         }
7559         var ret = false;
7560         try {
7561             ret = Roo.decode(response.responseText);
7562         } catch (e) {
7563             ret = {
7564                 success: false,
7565                 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7566                 errors : []
7567             };
7568         }
7569         return ret;
7570         
7571     }
7572 });
7573
7574
7575 Roo.form.Action.Load = function(form, options){
7576     Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7577     this.reader = this.form.reader;
7578 };
7579
7580 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7581     type : 'load',
7582
7583     run : function(){
7584         
7585         Roo.Ajax.request(Roo.apply(
7586                 this.createCallback(), {
7587                     method:this.getMethod(),
7588                     url:this.getUrl(false),
7589                     params:this.getParams()
7590         }));
7591     },
7592
7593     success : function(response){
7594         
7595         var result = this.processResponse(response);
7596         if(result === true || !result.success || !result.data){
7597             this.failureType = Roo.form.Action.LOAD_FAILURE;
7598             this.form.afterAction(this, false);
7599             return;
7600         }
7601         this.form.clearInvalid();
7602         this.form.setValues(result.data);
7603         this.form.afterAction(this, true);
7604     },
7605
7606     handleResponse : function(response){
7607         if(this.form.reader){
7608             var rs = this.form.reader.read(response);
7609             var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7610             return {
7611                 success : rs.success,
7612                 data : data
7613             };
7614         }
7615         return Roo.decode(response.responseText);
7616     }
7617 });
7618
7619 Roo.form.Action.ACTION_TYPES = {
7620     'load' : Roo.form.Action.Load,
7621     'submit' : Roo.form.Action.Submit
7622 };/*
7623  * - LGPL
7624  *
7625  * form
7626  *
7627  */
7628
7629 /**
7630  * @class Roo.bootstrap.Form
7631  * @extends Roo.bootstrap.Component
7632  * Bootstrap Form class
7633  * @cfg {String} method  GET | POST (default POST)
7634  * @cfg {String} labelAlign top | left (default top)
7635  * @cfg {String} align left  | right - for navbars
7636  * @cfg {Boolean} loadMask load mask when submit (default true)
7637
7638  *
7639  * @constructor
7640  * Create a new Form
7641  * @param {Object} config The config object
7642  */
7643
7644
7645 Roo.bootstrap.Form = function(config){
7646     
7647     Roo.bootstrap.Form.superclass.constructor.call(this, config);
7648     
7649     Roo.bootstrap.Form.popover.apply();
7650     
7651     this.addEvents({
7652         /**
7653          * @event clientvalidation
7654          * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7655          * @param {Form} this
7656          * @param {Boolean} valid true if the form has passed client-side validation
7657          */
7658         clientvalidation: true,
7659         /**
7660          * @event beforeaction
7661          * Fires before any action is performed. Return false to cancel the action.
7662          * @param {Form} this
7663          * @param {Action} action The action to be performed
7664          */
7665         beforeaction: true,
7666         /**
7667          * @event actionfailed
7668          * Fires when an action fails.
7669          * @param {Form} this
7670          * @param {Action} action The action that failed
7671          */
7672         actionfailed : true,
7673         /**
7674          * @event actioncomplete
7675          * Fires when an action is completed.
7676          * @param {Form} this
7677          * @param {Action} action The action that completed
7678          */
7679         actioncomplete : true
7680     });
7681 };
7682
7683 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component,  {
7684
7685      /**
7686      * @cfg {String} method
7687      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7688      */
7689     method : 'POST',
7690     /**
7691      * @cfg {String} url
7692      * The URL to use for form actions if one isn't supplied in the action options.
7693      */
7694     /**
7695      * @cfg {Boolean} fileUpload
7696      * Set to true if this form is a file upload.
7697      */
7698
7699     /**
7700      * @cfg {Object} baseParams
7701      * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7702      */
7703
7704     /**
7705      * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7706      */
7707     timeout: 30,
7708     /**
7709      * @cfg {Sting} align (left|right) for navbar forms
7710      */
7711     align : 'left',
7712
7713     // private
7714     activeAction : null,
7715
7716     /**
7717      * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
7718      * element by passing it or its id or mask the form itself by passing in true.
7719      * @type Mixed
7720      */
7721     waitMsgTarget : false,
7722
7723     loadMask : true,
7724     
7725     /**
7726      * @cfg {Boolean} errorMask (true|false) default false
7727      */
7728     errorMask : false,
7729     
7730     /**
7731      * @cfg {Number} maskOffset Default 100
7732      */
7733     maskOffset : 100,
7734     
7735     /**
7736      * @cfg {Boolean} maskBody
7737      */
7738     maskBody : false,
7739
7740     getAutoCreate : function(){
7741
7742         var cfg = {
7743             tag: 'form',
7744             method : this.method || 'POST',
7745             id : this.id || Roo.id(),
7746             cls : ''
7747         };
7748         if (this.parent().xtype.match(/^Nav/)) {
7749             cfg.cls = 'navbar-form navbar-' + this.align;
7750
7751         }
7752
7753         if (this.labelAlign == 'left' ) {
7754             cfg.cls += ' form-horizontal';
7755         }
7756
7757
7758         return cfg;
7759     },
7760     initEvents : function()
7761     {
7762         this.el.on('submit', this.onSubmit, this);
7763         // this was added as random key presses on the form where triggering form submit.
7764         this.el.on('keypress', function(e) {
7765             if (e.getCharCode() != 13) {
7766                 return true;
7767             }
7768             // we might need to allow it for textareas.. and some other items.
7769             // check e.getTarget().
7770
7771             if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
7772                 return true;
7773             }
7774
7775             Roo.log("keypress blocked");
7776
7777             e.preventDefault();
7778             return false;
7779         });
7780         
7781     },
7782     // private
7783     onSubmit : function(e){
7784         e.stopEvent();
7785     },
7786
7787      /**
7788      * Returns true if client-side validation on the form is successful.
7789      * @return Boolean
7790      */
7791     isValid : function(){
7792         var items = this.getItems();
7793         var valid = true;
7794         var target = false;
7795         
7796         items.each(function(f){
7797             
7798             if(f.validate()){
7799                 return;
7800             }
7801             
7802             valid = false;
7803
7804             if(!target && f.el.isVisible(true)){
7805                 target = f;
7806             }
7807            
7808         });
7809         
7810         if(this.errorMask && !valid){
7811             Roo.bootstrap.Form.popover.mask(this, target);
7812         }
7813         
7814         return valid;
7815     },
7816     
7817     /**
7818      * Returns true if any fields in this form have changed since their original load.
7819      * @return Boolean
7820      */
7821     isDirty : function(){
7822         var dirty = false;
7823         var items = this.getItems();
7824         items.each(function(f){
7825            if(f.isDirty()){
7826                dirty = true;
7827                return false;
7828            }
7829            return true;
7830         });
7831         return dirty;
7832     },
7833      /**
7834      * Performs a predefined action (submit or load) or custom actions you define on this form.
7835      * @param {String} actionName The name of the action type
7836      * @param {Object} options (optional) The options to pass to the action.  All of the config options listed
7837      * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
7838      * accept other config options):
7839      * <pre>
7840 Property          Type             Description
7841 ----------------  ---------------  ----------------------------------------------------------------------------------
7842 url               String           The url for the action (defaults to the form's url)
7843 method            String           The form method to use (defaults to the form's method, or POST if not defined)
7844 params            String/Object    The params to pass (defaults to the form's baseParams, or none if not defined)
7845 clientValidation  Boolean          Applies to submit only.  Pass true to call form.isValid() prior to posting to
7846                                    validate the form on the client (defaults to false)
7847      * </pre>
7848      * @return {BasicForm} this
7849      */
7850     doAction : function(action, options){
7851         if(typeof action == 'string'){
7852             action = new Roo.form.Action.ACTION_TYPES[action](this, options);
7853         }
7854         if(this.fireEvent('beforeaction', this, action) !== false){
7855             this.beforeAction(action);
7856             action.run.defer(100, action);
7857         }
7858         return this;
7859     },
7860
7861     // private
7862     beforeAction : function(action){
7863         var o = action.options;
7864         
7865         if(this.loadMask){
7866             
7867             if(this.maskBody){
7868                 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
7869             } else {
7870                 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7871             }
7872         }
7873         // not really supported yet.. ??
7874
7875         //if(this.waitMsgTarget === true){
7876         //  this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
7877         //}else if(this.waitMsgTarget){
7878         //    this.waitMsgTarget = Roo.get(this.waitMsgTarget);
7879         //    this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
7880         //}else {
7881         //    Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
7882        // }
7883
7884     },
7885
7886     // private
7887     afterAction : function(action, success){
7888         this.activeAction = null;
7889         var o = action.options;
7890
7891         if(this.loadMask){
7892             
7893             if(this.maskBody){
7894                 Roo.get(document.body).unmask();
7895             } else {
7896                 this.el.unmask();
7897             }
7898         }
7899         
7900         //if(this.waitMsgTarget === true){
7901 //            this.el.unmask();
7902         //}else if(this.waitMsgTarget){
7903         //    this.waitMsgTarget.unmask();
7904         //}else{
7905         //    Roo.MessageBox.updateProgress(1);
7906         //    Roo.MessageBox.hide();
7907        // }
7908         //
7909         if(success){
7910             if(o.reset){
7911                 this.reset();
7912             }
7913             Roo.callback(o.success, o.scope, [this, action]);
7914             this.fireEvent('actioncomplete', this, action);
7915
7916         }else{
7917
7918             // failure condition..
7919             // we have a scenario where updates need confirming.
7920             // eg. if a locking scenario exists..
7921             // we look for { errors : { needs_confirm : true }} in the response.
7922             if (
7923                 (typeof(action.result) != 'undefined')  &&
7924                 (typeof(action.result.errors) != 'undefined')  &&
7925                 (typeof(action.result.errors.needs_confirm) != 'undefined')
7926            ){
7927                 var _t = this;
7928                 Roo.log("not supported yet");
7929                  /*
7930
7931                 Roo.MessageBox.confirm(
7932                     "Change requires confirmation",
7933                     action.result.errorMsg,
7934                     function(r) {
7935                         if (r != 'yes') {
7936                             return;
7937                         }
7938                         _t.doAction('submit', { params :  { _submit_confirmed : 1 } }  );
7939                     }
7940
7941                 );
7942                 */
7943
7944
7945                 return;
7946             }
7947
7948             Roo.callback(o.failure, o.scope, [this, action]);
7949             // show an error message if no failed handler is set..
7950             if (!this.hasListener('actionfailed')) {
7951                 Roo.log("need to add dialog support");
7952                 /*
7953                 Roo.MessageBox.alert("Error",
7954                     (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7955                         action.result.errorMsg :
7956                         "Saving Failed, please check your entries or try again"
7957                 );
7958                 */
7959             }
7960
7961             this.fireEvent('actionfailed', this, action);
7962         }
7963
7964     },
7965     /**
7966      * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7967      * @param {String} id The value to search for
7968      * @return Field
7969      */
7970     findField : function(id){
7971         var items = this.getItems();
7972         var field = items.get(id);
7973         if(!field){
7974              items.each(function(f){
7975                 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7976                     field = f;
7977                     return false;
7978                 }
7979                 return true;
7980             });
7981         }
7982         return field || null;
7983     },
7984      /**
7985      * Mark fields in this form invalid in bulk.
7986      * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7987      * @return {BasicForm} this
7988      */
7989     markInvalid : function(errors){
7990         if(errors instanceof Array){
7991             for(var i = 0, len = errors.length; i < len; i++){
7992                 var fieldError = errors[i];
7993                 var f = this.findField(fieldError.id);
7994                 if(f){
7995                     f.markInvalid(fieldError.msg);
7996                 }
7997             }
7998         }else{
7999             var field, id;
8000             for(id in errors){
8001                 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8002                     field.markInvalid(errors[id]);
8003                 }
8004             }
8005         }
8006         //Roo.each(this.childForms || [], function (f) {
8007         //    f.markInvalid(errors);
8008         //});
8009
8010         return this;
8011     },
8012
8013     /**
8014      * Set values for fields in this form in bulk.
8015      * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8016      * @return {BasicForm} this
8017      */
8018     setValues : function(values){
8019         if(values instanceof Array){ // array of objects
8020             for(var i = 0, len = values.length; i < len; i++){
8021                 var v = values[i];
8022                 var f = this.findField(v.id);
8023                 if(f){
8024                     f.setValue(v.value);
8025                     if(this.trackResetOnLoad){
8026                         f.originalValue = f.getValue();
8027                     }
8028                 }
8029             }
8030         }else{ // object hash
8031             var field, id;
8032             for(id in values){
8033                 if(typeof values[id] != 'function' && (field = this.findField(id))){
8034
8035                     if (field.setFromData &&
8036                         field.valueField &&
8037                         field.displayField &&
8038                         // combos' with local stores can
8039                         // be queried via setValue()
8040                         // to set their value..
8041                         (field.store && !field.store.isLocal)
8042                         ) {
8043                         // it's a combo
8044                         var sd = { };
8045                         sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8046                         sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8047                         field.setFromData(sd);
8048
8049                     } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8050                         
8051                         field.setFromData(values);
8052                         
8053                     } else {
8054                         field.setValue(values[id]);
8055                     }
8056
8057
8058                     if(this.trackResetOnLoad){
8059                         field.originalValue = field.getValue();
8060                     }
8061                 }
8062             }
8063         }
8064
8065         //Roo.each(this.childForms || [], function (f) {
8066         //    f.setValues(values);
8067         //});
8068
8069         return this;
8070     },
8071
8072     /**
8073      * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8074      * they are returned as an array.
8075      * @param {Boolean} asString
8076      * @return {Object}
8077      */
8078     getValues : function(asString){
8079         //if (this.childForms) {
8080             // copy values from the child forms
8081         //    Roo.each(this.childForms, function (f) {
8082         //        this.setValues(f.getValues());
8083         //    }, this);
8084         //}
8085
8086
8087
8088         var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8089         if(asString === true){
8090             return fs;
8091         }
8092         return Roo.urlDecode(fs);
8093     },
8094
8095     /**
8096      * Returns the fields in this form as an object with key/value pairs.
8097      * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8098      * @return {Object}
8099      */
8100     getFieldValues : function(with_hidden)
8101     {
8102         var items = this.getItems();
8103         var ret = {};
8104         items.each(function(f){
8105             
8106             if (!f.getName()) {
8107                 return;
8108             }
8109             
8110             var v = f.getValue();
8111             
8112             if (f.inputType =='radio') {
8113                 if (typeof(ret[f.getName()]) == 'undefined') {
8114                     ret[f.getName()] = ''; // empty..
8115                 }
8116
8117                 if (!f.el.dom.checked) {
8118                     return;
8119
8120                 }
8121                 v = f.el.dom.value;
8122
8123             }
8124             
8125             if(f.xtype == 'MoneyField'){
8126                 ret[f.currencyName] = f.getCurrency();
8127             }
8128
8129             // not sure if this supported any more..
8130             if ((typeof(v) == 'object') && f.getRawValue) {
8131                 v = f.getRawValue() ; // dates..
8132             }
8133             // combo boxes where name != hiddenName...
8134             if (f.name !== false && f.name != '' && f.name != f.getName()) {
8135                 ret[f.name] = f.getRawValue();
8136             }
8137             ret[f.getName()] = v;
8138         });
8139
8140         return ret;
8141     },
8142
8143     /**
8144      * Clears all invalid messages in this form.
8145      * @return {BasicForm} this
8146      */
8147     clearInvalid : function(){
8148         var items = this.getItems();
8149
8150         items.each(function(f){
8151            f.clearInvalid();
8152         });
8153
8154         return this;
8155     },
8156
8157     /**
8158      * Resets this form.
8159      * @return {BasicForm} this
8160      */
8161     reset : function(){
8162         var items = this.getItems();
8163         items.each(function(f){
8164             f.reset();
8165         });
8166
8167         Roo.each(this.childForms || [], function (f) {
8168             f.reset();
8169         });
8170
8171
8172         return this;
8173     },
8174     
8175     getItems : function()
8176     {
8177         var r=new Roo.util.MixedCollection(false, function(o){
8178             return o.id || (o.id = Roo.id());
8179         });
8180         var iter = function(el) {
8181             if (el.inputEl) {
8182                 r.add(el);
8183             }
8184             if (!el.items) {
8185                 return;
8186             }
8187             Roo.each(el.items,function(e) {
8188                 iter(e);
8189             });
8190         };
8191
8192         iter(this);
8193         return r;
8194     },
8195     
8196     hideFields : function(items)
8197     {
8198         Roo.each(items, function(i){
8199             
8200             var f = this.findField(i);
8201             
8202             if(!f){
8203                 return;
8204             }
8205             
8206             if(f.xtype == 'DateField'){
8207                 f.setVisible(false);
8208                 return;
8209             }
8210             
8211             f.hide();
8212             
8213         }, this);
8214     },
8215     
8216     showFields : function(items)
8217     {
8218         Roo.each(items, function(i){
8219             
8220             var f = this.findField(i);
8221             
8222             if(!f){
8223                 return;
8224             }
8225             
8226             if(f.xtype == 'DateField'){
8227                 f.setVisible(true);
8228                 return;
8229             }
8230             
8231             f.show();
8232             
8233         }, this);
8234     }
8235
8236 });
8237
8238 Roo.apply(Roo.bootstrap.Form, {
8239     
8240     popover : {
8241         
8242         padding : 5,
8243         
8244         isApplied : false,
8245         
8246         isMasked : false,
8247         
8248         form : false,
8249         
8250         target : false,
8251         
8252         toolTip : false,
8253         
8254         intervalID : false,
8255         
8256         maskEl : false,
8257         
8258         apply : function()
8259         {
8260             if(this.isApplied){
8261                 return;
8262             }
8263             
8264             this.maskEl = {
8265                 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8266                 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8267                 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8268                 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8269             };
8270             
8271             this.maskEl.top.enableDisplayMode("block");
8272             this.maskEl.left.enableDisplayMode("block");
8273             this.maskEl.bottom.enableDisplayMode("block");
8274             this.maskEl.right.enableDisplayMode("block");
8275             
8276             this.toolTip = new Roo.bootstrap.Tooltip({
8277                 cls : 'roo-form-error-popover',
8278                 alignment : {
8279                     'left' : ['r-l', [-2,0], 'right'],
8280                     'right' : ['l-r', [2,0], 'left'],
8281                     'bottom' : ['tl-bl', [0,2], 'top'],
8282                     'top' : [ 'bl-tl', [0,-2], 'bottom']
8283                 }
8284             });
8285             
8286             this.toolTip.render(Roo.get(document.body));
8287
8288             this.toolTip.el.enableDisplayMode("block");
8289             
8290             Roo.get(document.body).on('click', function(){
8291                 this.unmask();
8292             }, this);
8293             
8294             Roo.get(document.body).on('touchstart', function(){
8295                 this.unmask();
8296             }, this);
8297             
8298             this.isApplied = true
8299         },
8300         
8301         mask : function(form, target)
8302         {
8303             this.form = form;
8304             
8305             this.target = target;
8306             
8307             if(!this.form.errorMask || !target.el){
8308                 return;
8309             }
8310             
8311             var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8312             
8313             Roo.log(scrollable);
8314             
8315             var ot = this.target.el.calcOffsetsTo(scrollable);
8316             
8317             var scrollTo = ot[1] - this.form.maskOffset;
8318             
8319             scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8320             
8321             scrollable.scrollTo('top', scrollTo);
8322             
8323             var box = this.target.el.getBox();
8324             Roo.log(box);
8325             var zIndex = Roo.bootstrap.Modal.zIndex++;
8326
8327             
8328             this.maskEl.top.setStyle('position', 'absolute');
8329             this.maskEl.top.setStyle('z-index', zIndex);
8330             this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8331             this.maskEl.top.setLeft(0);
8332             this.maskEl.top.setTop(0);
8333             this.maskEl.top.show();
8334             
8335             this.maskEl.left.setStyle('position', 'absolute');
8336             this.maskEl.left.setStyle('z-index', zIndex);
8337             this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8338             this.maskEl.left.setLeft(0);
8339             this.maskEl.left.setTop(box.y - this.padding);
8340             this.maskEl.left.show();
8341
8342             this.maskEl.bottom.setStyle('position', 'absolute');
8343             this.maskEl.bottom.setStyle('z-index', zIndex);
8344             this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8345             this.maskEl.bottom.setLeft(0);
8346             this.maskEl.bottom.setTop(box.bottom + this.padding);
8347             this.maskEl.bottom.show();
8348
8349             this.maskEl.right.setStyle('position', 'absolute');
8350             this.maskEl.right.setStyle('z-index', zIndex);
8351             this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8352             this.maskEl.right.setLeft(box.right + this.padding);
8353             this.maskEl.right.setTop(box.y - this.padding);
8354             this.maskEl.right.show();
8355
8356             this.toolTip.bindEl = this.target.el;
8357
8358             this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8359
8360             var tip = this.target.blankText;
8361
8362             if(this.target.getValue() !== '' ) {
8363                 
8364                 if (this.target.invalidText.length) {
8365                     tip = this.target.invalidText;
8366                 } else if (this.target.regexText.length){
8367                     tip = this.target.regexText;
8368                 }
8369             }
8370
8371             this.toolTip.show(tip);
8372
8373             this.intervalID = window.setInterval(function() {
8374                 Roo.bootstrap.Form.popover.unmask();
8375             }, 10000);
8376
8377             window.onwheel = function(){ return false;};
8378             
8379             (function(){ this.isMasked = true; }).defer(500, this);
8380             
8381         },
8382         
8383         unmask : function()
8384         {
8385             if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8386                 return;
8387             }
8388             
8389             this.maskEl.top.setStyle('position', 'absolute');
8390             this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8391             this.maskEl.top.hide();
8392
8393             this.maskEl.left.setStyle('position', 'absolute');
8394             this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8395             this.maskEl.left.hide();
8396
8397             this.maskEl.bottom.setStyle('position', 'absolute');
8398             this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8399             this.maskEl.bottom.hide();
8400
8401             this.maskEl.right.setStyle('position', 'absolute');
8402             this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8403             this.maskEl.right.hide();
8404             
8405             this.toolTip.hide();
8406             
8407             this.toolTip.el.hide();
8408             
8409             window.onwheel = function(){ return true;};
8410             
8411             if(this.intervalID){
8412                 window.clearInterval(this.intervalID);
8413                 this.intervalID = false;
8414             }
8415             
8416             this.isMasked = false;
8417             
8418         }
8419         
8420     }
8421     
8422 });
8423
8424 /*
8425  * Based on:
8426  * Ext JS Library 1.1.1
8427  * Copyright(c) 2006-2007, Ext JS, LLC.
8428  *
8429  * Originally Released Under LGPL - original licence link has changed is not relivant.
8430  *
8431  * Fork - LGPL
8432  * <script type="text/javascript">
8433  */
8434 /**
8435  * @class Roo.form.VTypes
8436  * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8437  * @singleton
8438  */
8439 Roo.form.VTypes = function(){
8440     // closure these in so they are only created once.
8441     var alpha = /^[a-zA-Z_]+$/;
8442     var alphanum = /^[a-zA-Z0-9_]+$/;
8443     var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8444     var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8445
8446     // All these messages and functions are configurable
8447     return {
8448         /**
8449          * The function used to validate email addresses
8450          * @param {String} value The email address
8451          */
8452         'email' : function(v){
8453             return email.test(v);
8454         },
8455         /**
8456          * The error text to display when the email validation function returns false
8457          * @type String
8458          */
8459         'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8460         /**
8461          * The keystroke filter mask to be applied on email input
8462          * @type RegExp
8463          */
8464         'emailMask' : /[a-z0-9_\.\-@]/i,
8465
8466         /**
8467          * The function used to validate URLs
8468          * @param {String} value The URL
8469          */
8470         'url' : function(v){
8471             return url.test(v);
8472         },
8473         /**
8474          * The error text to display when the url validation function returns false
8475          * @type String
8476          */
8477         'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8478         
8479         /**
8480          * The function used to validate alpha values
8481          * @param {String} value The value
8482          */
8483         'alpha' : function(v){
8484             return alpha.test(v);
8485         },
8486         /**
8487          * The error text to display when the alpha validation function returns false
8488          * @type String
8489          */
8490         'alphaText' : 'This field should only contain letters and _',
8491         /**
8492          * The keystroke filter mask to be applied on alpha input
8493          * @type RegExp
8494          */
8495         'alphaMask' : /[a-z_]/i,
8496
8497         /**
8498          * The function used to validate alphanumeric values
8499          * @param {String} value The value
8500          */
8501         'alphanum' : function(v){
8502             return alphanum.test(v);
8503         },
8504         /**
8505          * The error text to display when the alphanumeric validation function returns false
8506          * @type String
8507          */
8508         'alphanumText' : 'This field should only contain letters, numbers and _',
8509         /**
8510          * The keystroke filter mask to be applied on alphanumeric input
8511          * @type RegExp
8512          */
8513         'alphanumMask' : /[a-z0-9_]/i
8514     };
8515 }();/*
8516  * - LGPL
8517  *
8518  * Input
8519  * 
8520  */
8521
8522 /**
8523  * @class Roo.bootstrap.Input
8524  * @extends Roo.bootstrap.Component
8525  * Bootstrap Input class
8526  * @cfg {Boolean} disabled is it disabled
8527  * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8528  * @cfg {String} name name of the input
8529  * @cfg {string} fieldLabel - the label associated
8530  * @cfg {string} placeholder - placeholder to put in text.
8531  * @cfg {string}  before - input group add on before
8532  * @cfg {string} after - input group add on after
8533  * @cfg {string} size - (lg|sm) or leave empty..
8534  * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8535  * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8536  * @cfg {Number} md colspan out of 12 for computer-sized screens
8537  * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8538  * @cfg {string} value default value of the input
8539  * @cfg {Number} labelWidth set the width of label 
8540  * @cfg {Number} labellg set the width of label (1-12)
8541  * @cfg {Number} labelmd set the width of label (1-12)
8542  * @cfg {Number} labelsm set the width of label (1-12)
8543  * @cfg {Number} labelxs set the width of label (1-12)
8544  * @cfg {String} labelAlign (top|left)
8545  * @cfg {Boolean} readOnly Specifies that the field should be read-only
8546  * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8547  * @cfg {String} indicatorpos (left|right) default left
8548  * @cfg {String} capture (user|camera) use for file input only. (default empty)
8549  * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8550
8551  * @cfg {String} align (left|center|right) Default left
8552  * @cfg {Boolean} forceFeedback (true|false) Default false
8553  * 
8554  * @constructor
8555  * Create a new Input
8556  * @param {Object} config The config object
8557  */
8558
8559 Roo.bootstrap.Input = function(config){
8560     
8561     Roo.bootstrap.Input.superclass.constructor.call(this, config);
8562     
8563     this.addEvents({
8564         /**
8565          * @event focus
8566          * Fires when this field receives input focus.
8567          * @param {Roo.form.Field} this
8568          */
8569         focus : true,
8570         /**
8571          * @event blur
8572          * Fires when this field loses input focus.
8573          * @param {Roo.form.Field} this
8574          */
8575         blur : true,
8576         /**
8577          * @event specialkey
8578          * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed.  You can check
8579          * {@link Roo.EventObject#getKey} to determine which key was pressed.
8580          * @param {Roo.form.Field} this
8581          * @param {Roo.EventObject} e The event object
8582          */
8583         specialkey : true,
8584         /**
8585          * @event change
8586          * Fires just before the field blurs if the field value has changed.
8587          * @param {Roo.form.Field} this
8588          * @param {Mixed} newValue The new value
8589          * @param {Mixed} oldValue The original value
8590          */
8591         change : true,
8592         /**
8593          * @event invalid
8594          * Fires after the field has been marked as invalid.
8595          * @param {Roo.form.Field} this
8596          * @param {String} msg The validation message
8597          */
8598         invalid : true,
8599         /**
8600          * @event valid
8601          * Fires after the field has been validated with no errors.
8602          * @param {Roo.form.Field} this
8603          */
8604         valid : true,
8605          /**
8606          * @event keyup
8607          * Fires after the key up
8608          * @param {Roo.form.Field} this
8609          * @param {Roo.EventObject}  e The event Object
8610          */
8611         keyup : true
8612     });
8613 };
8614
8615 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component,  {
8616      /**
8617      * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8618       automatic validation (defaults to "keyup").
8619      */
8620     validationEvent : "keyup",
8621      /**
8622      * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8623      */
8624     validateOnBlur : true,
8625     /**
8626      * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8627      */
8628     validationDelay : 250,
8629      /**
8630      * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8631      */
8632     focusClass : "x-form-focus",  // not needed???
8633     
8634        
8635     /**
8636      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8637      */
8638     invalidClass : "has-warning",
8639     
8640     /**
8641      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8642      */
8643     validClass : "has-success",
8644     
8645     /**
8646      * @cfg {Boolean} hasFeedback (true|false) default true
8647      */
8648     hasFeedback : true,
8649     
8650     /**
8651      * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8652      */
8653     invalidFeedbackClass : "glyphicon-warning-sign",
8654     
8655     /**
8656      * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8657      */
8658     validFeedbackClass : "glyphicon-ok",
8659     
8660     /**
8661      * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8662      */
8663     selectOnFocus : false,
8664     
8665      /**
8666      * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8667      */
8668     maskRe : null,
8669        /**
8670      * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8671      */
8672     vtype : null,
8673     
8674       /**
8675      * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8676      */
8677     disableKeyFilter : false,
8678     
8679        /**
8680      * @cfg {Boolean} disabled True to disable the field (defaults to false).
8681      */
8682     disabled : false,
8683      /**
8684      * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8685      */
8686     allowBlank : true,
8687     /**
8688      * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8689      */
8690     blankText : "Please complete this mandatory field",
8691     
8692      /**
8693      * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8694      */
8695     minLength : 0,
8696     /**
8697      * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8698      */
8699     maxLength : Number.MAX_VALUE,
8700     /**
8701      * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8702      */
8703     minLengthText : "The minimum length for this field is {0}",
8704     /**
8705      * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8706      */
8707     maxLengthText : "The maximum length for this field is {0}",
8708   
8709     
8710     /**
8711      * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8712      * If available, this function will be called only after the basic validators all return true, and will be passed the
8713      * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8714      */
8715     validator : null,
8716     /**
8717      * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8718      * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8719      * current field value.  If the test fails, the field will be marked invalid using {@link #regexText}.
8720      */
8721     regex : null,
8722     /**
8723      * @cfg {String} regexText -- Depricated - use Invalid Text
8724      */
8725     regexText : "",
8726     
8727     /**
8728      * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
8729      */
8730     invalidText : "",
8731     
8732     
8733     
8734     autocomplete: false,
8735     
8736     
8737     fieldLabel : '',
8738     inputType : 'text',
8739     
8740     name : false,
8741     placeholder: false,
8742     before : false,
8743     after : false,
8744     size : false,
8745     hasFocus : false,
8746     preventMark: false,
8747     isFormField : true,
8748     value : '',
8749     labelWidth : 2,
8750     labelAlign : false,
8751     readOnly : false,
8752     align : false,
8753     formatedValue : false,
8754     forceFeedback : false,
8755     
8756     indicatorpos : 'left',
8757     
8758     labellg : 0,
8759     labelmd : 0,
8760     labelsm : 0,
8761     labelxs : 0,
8762     
8763     capture : '',
8764     accept : '',
8765     
8766     parentLabelAlign : function()
8767     {
8768         var parent = this;
8769         while (parent.parent()) {
8770             parent = parent.parent();
8771             if (typeof(parent.labelAlign) !='undefined') {
8772                 return parent.labelAlign;
8773             }
8774         }
8775         return 'left';
8776         
8777     },
8778     
8779     getAutoCreate : function()
8780     {
8781         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8782         
8783         var id = Roo.id();
8784         
8785         var cfg = {};
8786         
8787         if(this.inputType != 'hidden'){
8788             cfg.cls = 'form-group' //input-group
8789         }
8790         
8791         var input =  {
8792             tag: 'input',
8793             id : id,
8794             type : this.inputType,
8795             value : this.value,
8796             cls : 'form-control',
8797             placeholder : this.placeholder || '',
8798             autocomplete : this.autocomplete || 'new-password'
8799         };
8800         
8801         if(this.capture.length){
8802             input.capture = this.capture;
8803         }
8804         
8805         if(this.accept.length){
8806             input.accept = this.accept + "/*";
8807         }
8808         
8809         if(this.align){
8810             input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
8811         }
8812         
8813         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8814             input.maxLength = this.maxLength;
8815         }
8816         
8817         if (this.disabled) {
8818             input.disabled=true;
8819         }
8820         
8821         if (this.readOnly) {
8822             input.readonly=true;
8823         }
8824         
8825         if (this.name) {
8826             input.name = this.name;
8827         }
8828         
8829         if (this.size) {
8830             input.cls += ' input-' + this.size;
8831         }
8832         
8833         var settings=this;
8834         ['xs','sm','md','lg'].map(function(size){
8835             if (settings[size]) {
8836                 cfg.cls += ' col-' + size + '-' + settings[size];
8837             }
8838         });
8839         
8840         var inputblock = input;
8841         
8842         var feedback = {
8843             tag: 'span',
8844             cls: 'glyphicon form-control-feedback'
8845         };
8846             
8847         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8848             
8849             inputblock = {
8850                 cls : 'has-feedback',
8851                 cn :  [
8852                     input,
8853                     feedback
8854                 ] 
8855             };  
8856         }
8857         
8858         if (this.before || this.after) {
8859             
8860             inputblock = {
8861                 cls : 'input-group',
8862                 cn :  [] 
8863             };
8864             
8865             if (this.before && typeof(this.before) == 'string') {
8866                 
8867                 inputblock.cn.push({
8868                     tag :'span',
8869                     cls : 'roo-input-before input-group-addon',
8870                     html : this.before
8871                 });
8872             }
8873             if (this.before && typeof(this.before) == 'object') {
8874                 this.before = Roo.factory(this.before);
8875                 
8876                 inputblock.cn.push({
8877                     tag :'span',
8878                     cls : 'roo-input-before input-group-' +
8879                         (this.before.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8880                 });
8881             }
8882             
8883             inputblock.cn.push(input);
8884             
8885             if (this.after && typeof(this.after) == 'string') {
8886                 inputblock.cn.push({
8887                     tag :'span',
8888                     cls : 'roo-input-after input-group-addon',
8889                     html : this.after
8890                 });
8891             }
8892             if (this.after && typeof(this.after) == 'object') {
8893                 this.after = Roo.factory(this.after);
8894                 
8895                 inputblock.cn.push({
8896                     tag :'span',
8897                     cls : 'roo-input-after input-group-' +
8898                         (this.after.xtype == 'Button' ? 'btn' : 'addon')  //?? what about checkboxes - that looks like a bit of a hack thought? 
8899                 });
8900             }
8901             
8902             if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8903                 inputblock.cls += ' has-feedback';
8904                 inputblock.cn.push(feedback);
8905             }
8906         };
8907         
8908         if (align ==='left' && this.fieldLabel.length) {
8909             
8910             cfg.cls += ' roo-form-group-label-left';
8911             
8912             cfg.cn = [
8913                 {
8914                     tag : 'i',
8915                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
8916                     tooltip : 'This field is required'
8917                 },
8918                 {
8919                     tag: 'label',
8920                     'for' :  id,
8921                     cls : 'control-label',
8922                     html : this.fieldLabel
8923
8924                 },
8925                 {
8926                     cls : "", 
8927                     cn: [
8928                         inputblock
8929                     ]
8930                 }
8931             ];
8932             
8933             var labelCfg = cfg.cn[1];
8934             var contentCfg = cfg.cn[2];
8935             
8936             if(this.indicatorpos == 'right'){
8937                 cfg.cn = [
8938                     {
8939                         tag: 'label',
8940                         'for' :  id,
8941                         cls : 'control-label',
8942                         cn : [
8943                             {
8944                                 tag : 'span',
8945                                 html : this.fieldLabel
8946                             },
8947                             {
8948                                 tag : 'i',
8949                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
8950                                 tooltip : 'This field is required'
8951                             }
8952                         ]
8953                     },
8954                     {
8955                         cls : "",
8956                         cn: [
8957                             inputblock
8958                         ]
8959                     }
8960
8961                 ];
8962                 
8963                 labelCfg = cfg.cn[0];
8964                 contentCfg = cfg.cn[1];
8965             
8966             }
8967             
8968             if(this.labelWidth > 12){
8969                 labelCfg.style = "width: " + this.labelWidth + 'px';
8970             }
8971             
8972             if(this.labelWidth < 13 && this.labelmd == 0){
8973                 this.labelmd = this.labelWidth;
8974             }
8975             
8976             if(this.labellg > 0){
8977                 labelCfg.cls += ' col-lg-' + this.labellg;
8978                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
8979             }
8980             
8981             if(this.labelmd > 0){
8982                 labelCfg.cls += ' col-md-' + this.labelmd;
8983                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
8984             }
8985             
8986             if(this.labelsm > 0){
8987                 labelCfg.cls += ' col-sm-' + this.labelsm;
8988                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
8989             }
8990             
8991             if(this.labelxs > 0){
8992                 labelCfg.cls += ' col-xs-' + this.labelxs;
8993                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
8994             }
8995             
8996             
8997         } else if ( this.fieldLabel.length) {
8998                 
8999             cfg.cn = [
9000                 {
9001                     tag : 'i',
9002                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9003                     tooltip : 'This field is required'
9004                 },
9005                 {
9006                     tag: 'label',
9007                    //cls : 'input-group-addon',
9008                     html : this.fieldLabel
9009
9010                 },
9011
9012                inputblock
9013
9014            ];
9015            
9016            if(this.indicatorpos == 'right'){
9017                 
9018                 cfg.cn = [
9019                     {
9020                         tag: 'label',
9021                        //cls : 'input-group-addon',
9022                         html : this.fieldLabel
9023
9024                     },
9025                     {
9026                         tag : 'i',
9027                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9028                         tooltip : 'This field is required'
9029                     },
9030
9031                    inputblock
9032
9033                ];
9034
9035             }
9036
9037         } else {
9038             
9039             cfg.cn = [
9040
9041                     inputblock
9042
9043             ];
9044                 
9045                 
9046         };
9047         
9048         if (this.parentType === 'Navbar' &&  this.parent().bar) {
9049            cfg.cls += ' navbar-form';
9050         }
9051         
9052         if (this.parentType === 'NavGroup') {
9053            cfg.cls += ' navbar-form';
9054            cfg.tag = 'li';
9055         }
9056         
9057         return cfg;
9058         
9059     },
9060     /**
9061      * return the real input element.
9062      */
9063     inputEl: function ()
9064     {
9065         return this.el.select('input.form-control',true).first();
9066     },
9067     
9068     tooltipEl : function()
9069     {
9070         return this.inputEl();
9071     },
9072     
9073     indicatorEl : function()
9074     {
9075         var indicator = this.el.select('i.roo-required-indicator',true).first();
9076         
9077         if(!indicator){
9078             return false;
9079         }
9080         
9081         return indicator;
9082         
9083     },
9084     
9085     setDisabled : function(v)
9086     {
9087         var i  = this.inputEl().dom;
9088         if (!v) {
9089             i.removeAttribute('disabled');
9090             return;
9091             
9092         }
9093         i.setAttribute('disabled','true');
9094     },
9095     initEvents : function()
9096     {
9097           
9098         this.inputEl().on("keydown" , this.fireKey,  this);
9099         this.inputEl().on("focus", this.onFocus,  this);
9100         this.inputEl().on("blur", this.onBlur,  this);
9101         
9102         this.inputEl().relayEvent('keyup', this);
9103         
9104         this.indicator = this.indicatorEl();
9105         
9106         if(this.indicator){
9107             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? - 
9108         }
9109  
9110         // reference to original value for reset
9111         this.originalValue = this.getValue();
9112         //Roo.form.TextField.superclass.initEvents.call(this);
9113         if(this.validationEvent == 'keyup'){
9114             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9115             this.inputEl().on('keyup', this.filterValidation, this);
9116         }
9117         else if(this.validationEvent !== false){
9118             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9119         }
9120         
9121         if(this.selectOnFocus){
9122             this.on("focus", this.preFocus, this);
9123             
9124         }
9125         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9126             this.inputEl().on("keypress", this.filterKeys, this);
9127         } else {
9128             this.inputEl().relayEvent('keypress', this);
9129         }
9130        /* if(this.grow){
9131             this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
9132             this.el.on("click", this.autoSize,  this);
9133         }
9134         */
9135         if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9136             this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9137         }
9138         
9139         if (typeof(this.before) == 'object') {
9140             this.before.render(this.el.select('.roo-input-before',true).first());
9141         }
9142         if (typeof(this.after) == 'object') {
9143             this.after.render(this.el.select('.roo-input-after',true).first());
9144         }
9145         
9146         this.inputEl().on('change', this.onChange, this);
9147         
9148     },
9149     filterValidation : function(e){
9150         if(!e.isNavKeyPress()){
9151             this.validationTask.delay(this.validationDelay);
9152         }
9153     },
9154      /**
9155      * Validates the field value
9156      * @return {Boolean} True if the value is valid, else false
9157      */
9158     validate : function(){
9159         //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9160         if(this.disabled || this.validateValue(this.getRawValue())){
9161             this.markValid();
9162             return true;
9163         }
9164         
9165         this.markInvalid();
9166         return false;
9167     },
9168     
9169     
9170     /**
9171      * Validates a value according to the field's validation rules and marks the field as invalid
9172      * if the validation fails
9173      * @param {Mixed} value The value to validate
9174      * @return {Boolean} True if the value is valid, else false
9175      */
9176     validateValue : function(value)
9177     {
9178         if(this.getVisibilityEl().hasClass('hidden')){
9179             return true;
9180         }
9181         
9182         if(value.length < 1)  { // if it's blank
9183             if(this.allowBlank){
9184                 return true;
9185             }
9186             return false;
9187         }
9188         
9189         if(value.length < this.minLength){
9190             return false;
9191         }
9192         if(value.length > this.maxLength){
9193             return false;
9194         }
9195         if(this.vtype){
9196             var vt = Roo.form.VTypes;
9197             if(!vt[this.vtype](value, this)){
9198                 return false;
9199             }
9200         }
9201         if(typeof this.validator == "function"){
9202             var msg = this.validator(value);
9203             if(msg !== true){
9204                 return false;
9205             }
9206             if (typeof(msg) == 'string') {
9207                 this.invalidText = msg;
9208             }
9209         }
9210         
9211         if(this.regex && !this.regex.test(value)){
9212             return false;
9213         }
9214         
9215         return true;
9216     },
9217     
9218      // private
9219     fireKey : function(e){
9220         //Roo.log('field ' + e.getKey());
9221         if(e.isNavKeyPress()){
9222             this.fireEvent("specialkey", this, e);
9223         }
9224     },
9225     focus : function (selectText){
9226         if(this.rendered){
9227             this.inputEl().focus();
9228             if(selectText === true){
9229                 this.inputEl().dom.select();
9230             }
9231         }
9232         return this;
9233     } ,
9234     
9235     onFocus : function(){
9236         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9237            // this.el.addClass(this.focusClass);
9238         }
9239         if(!this.hasFocus){
9240             this.hasFocus = true;
9241             this.startValue = this.getValue();
9242             this.fireEvent("focus", this);
9243         }
9244     },
9245     
9246     beforeBlur : Roo.emptyFn,
9247
9248     
9249     // private
9250     onBlur : function(){
9251         this.beforeBlur();
9252         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9253             //this.el.removeClass(this.focusClass);
9254         }
9255         this.hasFocus = false;
9256         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9257             this.validate();
9258         }
9259         var v = this.getValue();
9260         if(String(v) !== String(this.startValue)){
9261             this.fireEvent('change', this, v, this.startValue);
9262         }
9263         this.fireEvent("blur", this);
9264     },
9265     
9266     onChange : function(e)
9267     {
9268         var v = this.getValue();
9269         if(String(v) !== String(this.startValue)){
9270             this.fireEvent('change', this, v, this.startValue);
9271         }
9272         
9273     },
9274     
9275     /**
9276      * Resets the current field value to the originally loaded value and clears any validation messages
9277      */
9278     reset : function(){
9279         this.setValue(this.originalValue);
9280         this.validate();
9281     },
9282      /**
9283      * Returns the name of the field
9284      * @return {Mixed} name The name field
9285      */
9286     getName: function(){
9287         return this.name;
9288     },
9289      /**
9290      * Returns the normalized data value (undefined or emptyText will be returned as '').  To return the raw value see {@link #getRawValue}.
9291      * @return {Mixed} value The field value
9292      */
9293     getValue : function(){
9294         
9295         var v = this.inputEl().getValue();
9296         
9297         return v;
9298     },
9299     /**
9300      * Returns the raw data value which may or may not be a valid, defined value.  To return a normalized value see {@link #getValue}.
9301      * @return {Mixed} value The field value
9302      */
9303     getRawValue : function(){
9304         var v = this.inputEl().getValue();
9305         
9306         return v;
9307     },
9308     
9309     /**
9310      * Sets the underlying DOM field's value directly, bypassing validation.  To set the value with validation see {@link #setValue}.
9311      * @param {Mixed} value The value to set
9312      */
9313     setRawValue : function(v){
9314         return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9315     },
9316     
9317     selectText : function(start, end){
9318         var v = this.getRawValue();
9319         if(v.length > 0){
9320             start = start === undefined ? 0 : start;
9321             end = end === undefined ? v.length : end;
9322             var d = this.inputEl().dom;
9323             if(d.setSelectionRange){
9324                 d.setSelectionRange(start, end);
9325             }else if(d.createTextRange){
9326                 var range = d.createTextRange();
9327                 range.moveStart("character", start);
9328                 range.moveEnd("character", v.length-end);
9329                 range.select();
9330             }
9331         }
9332     },
9333     
9334     /**
9335      * Sets a data value into the field and validates it.  To set the value directly without validation see {@link #setRawValue}.
9336      * @param {Mixed} value The value to set
9337      */
9338     setValue : function(v){
9339         this.value = v;
9340         if(this.rendered){
9341             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9342             this.validate();
9343         }
9344     },
9345     
9346     /*
9347     processValue : function(value){
9348         if(this.stripCharsRe){
9349             var newValue = value.replace(this.stripCharsRe, '');
9350             if(newValue !== value){
9351                 this.setRawValue(newValue);
9352                 return newValue;
9353             }
9354         }
9355         return value;
9356     },
9357   */
9358     preFocus : function(){
9359         
9360         if(this.selectOnFocus){
9361             this.inputEl().dom.select();
9362         }
9363     },
9364     filterKeys : function(e){
9365         var k = e.getKey();
9366         if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9367             return;
9368         }
9369         var c = e.getCharCode(), cc = String.fromCharCode(c);
9370         if(Roo.isIE && (e.isSpecialKey() || !cc)){
9371             return;
9372         }
9373         if(!this.maskRe.test(cc)){
9374             e.stopEvent();
9375         }
9376     },
9377      /**
9378      * Clear any invalid styles/messages for this field
9379      */
9380     clearInvalid : function(){
9381         
9382         if(!this.el || this.preventMark){ // not rendered
9383             return;
9384         }
9385         
9386      
9387         this.el.removeClass(this.invalidClass);
9388         
9389         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9390             
9391             var feedback = this.el.select('.form-control-feedback', true).first();
9392             
9393             if(feedback){
9394                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9395             }
9396             
9397         }
9398         
9399         this.fireEvent('valid', this);
9400     },
9401     
9402      /**
9403      * Mark this field as valid
9404      */
9405     markValid : function()
9406     {
9407         if(!this.el  || this.preventMark){ // not rendered...
9408             return;
9409         }
9410         
9411         this.el.removeClass([this.invalidClass, this.validClass]);
9412         
9413         var feedback = this.el.select('.form-control-feedback', true).first();
9414             
9415         if(feedback){
9416             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9417         }
9418         
9419         if(this.indicator){
9420             this.indicator.removeClass('visible');
9421             this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9422         }
9423         
9424         if(this.disabled){
9425             return;
9426         }
9427         
9428         if(this.allowBlank && !this.getRawValue().length){
9429             return;
9430         }
9431         
9432         this.el.addClass(this.validClass);
9433         
9434         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9435             
9436             var feedback = this.el.select('.form-control-feedback', true).first();
9437             
9438             if(feedback){
9439                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9440                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9441             }
9442             
9443         }
9444         
9445         this.fireEvent('valid', this);
9446     },
9447     
9448      /**
9449      * Mark this field as invalid
9450      * @param {String} msg The validation message
9451      */
9452     markInvalid : function(msg)
9453     {
9454         if(!this.el  || this.preventMark){ // not rendered
9455             return;
9456         }
9457         
9458         this.el.removeClass([this.invalidClass, this.validClass]);
9459         
9460         var feedback = this.el.select('.form-control-feedback', true).first();
9461             
9462         if(feedback){
9463             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9464         }
9465
9466         if(this.disabled){
9467             return;
9468         }
9469         
9470         if(this.allowBlank && !this.getRawValue().length){
9471             return;
9472         }
9473         
9474         if(this.indicator){
9475             this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9476             this.indicator.addClass('visible');
9477         }
9478         
9479         this.el.addClass(this.invalidClass);
9480         
9481         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9482             
9483             var feedback = this.el.select('.form-control-feedback', true).first();
9484             
9485             if(feedback){
9486                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9487                 
9488                 if(this.getValue().length || this.forceFeedback){
9489                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9490                 }
9491                 
9492             }
9493             
9494         }
9495         
9496         this.fireEvent('invalid', this, msg);
9497     },
9498     // private
9499     SafariOnKeyDown : function(event)
9500     {
9501         // this is a workaround for a password hang bug on chrome/ webkit.
9502         if (this.inputEl().dom.type != 'password') {
9503             return;
9504         }
9505         
9506         var isSelectAll = false;
9507         
9508         if(this.inputEl().dom.selectionEnd > 0){
9509             isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9510         }
9511         if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9512             event.preventDefault();
9513             this.setValue('');
9514             return;
9515         }
9516         
9517         if(isSelectAll  && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9518             
9519             event.preventDefault();
9520             // this is very hacky as keydown always get's upper case.
9521             //
9522             var cc = String.fromCharCode(event.getCharCode());
9523             this.setValue( event.shiftKey ?  cc : cc.toLowerCase());
9524             
9525         }
9526     },
9527     adjustWidth : function(tag, w){
9528         tag = tag.toLowerCase();
9529         if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9530             if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9531                 if(tag == 'input'){
9532                     return w + 2;
9533                 }
9534                 if(tag == 'textarea'){
9535                     return w-2;
9536                 }
9537             }else if(Roo.isOpera){
9538                 if(tag == 'input'){
9539                     return w + 2;
9540                 }
9541                 if(tag == 'textarea'){
9542                     return w-2;
9543                 }
9544             }
9545         }
9546         return w;
9547     },
9548     
9549     setFieldLabel : function(v)
9550     {
9551         if(!this.rendered){
9552             return;
9553         }
9554         
9555         if(this.indicator){
9556             var ar = this.el.select('label > span',true);
9557             
9558             if (ar.elements.length) {
9559                 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9560                 this.fieldLabel = v;
9561                 return;
9562             }
9563             
9564             var br = this.el.select('label',true);
9565             
9566             if(br.elements.length) {
9567                 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9568                 this.fieldLabel = v;
9569                 return;
9570             }
9571             
9572             Roo.log('Cannot Found any of label > span || label in input');
9573             return;
9574         }
9575         
9576         this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9577         this.fieldLabel = v;
9578         
9579         
9580     }
9581 });
9582
9583  
9584 /*
9585  * - LGPL
9586  *
9587  * Input
9588  * 
9589  */
9590
9591 /**
9592  * @class Roo.bootstrap.TextArea
9593  * @extends Roo.bootstrap.Input
9594  * Bootstrap TextArea class
9595  * @cfg {Number} cols Specifies the visible width of a text area
9596  * @cfg {Number} rows Specifies the visible number of lines in a text area
9597  * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9598  * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9599  * @cfg {string} html text
9600  * 
9601  * @constructor
9602  * Create a new TextArea
9603  * @param {Object} config The config object
9604  */
9605
9606 Roo.bootstrap.TextArea = function(config){
9607     Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9608    
9609 };
9610
9611 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input,  {
9612      
9613     cols : false,
9614     rows : 5,
9615     readOnly : false,
9616     warp : 'soft',
9617     resize : false,
9618     value: false,
9619     html: false,
9620     
9621     getAutoCreate : function(){
9622         
9623         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9624         
9625         var id = Roo.id();
9626         
9627         var cfg = {};
9628         
9629         if(this.inputType != 'hidden'){
9630             cfg.cls = 'form-group' //input-group
9631         }
9632         
9633         var input =  {
9634             tag: 'textarea',
9635             id : id,
9636             warp : this.warp,
9637             rows : this.rows,
9638             value : this.value || '',
9639             html: this.html || '',
9640             cls : 'form-control',
9641             placeholder : this.placeholder || '' 
9642             
9643         };
9644         
9645         if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9646             input.maxLength = this.maxLength;
9647         }
9648         
9649         if(this.resize){
9650             input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9651         }
9652         
9653         if(this.cols){
9654             input.cols = this.cols;
9655         }
9656         
9657         if (this.readOnly) {
9658             input.readonly = true;
9659         }
9660         
9661         if (this.name) {
9662             input.name = this.name;
9663         }
9664         
9665         if (this.size) {
9666             input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9667         }
9668         
9669         var settings=this;
9670         ['xs','sm','md','lg'].map(function(size){
9671             if (settings[size]) {
9672                 cfg.cls += ' col-' + size + '-' + settings[size];
9673             }
9674         });
9675         
9676         var inputblock = input;
9677         
9678         if(this.hasFeedback && !this.allowBlank){
9679             
9680             var feedback = {
9681                 tag: 'span',
9682                 cls: 'glyphicon form-control-feedback'
9683             };
9684
9685             inputblock = {
9686                 cls : 'has-feedback',
9687                 cn :  [
9688                     input,
9689                     feedback
9690                 ] 
9691             };  
9692         }
9693         
9694         
9695         if (this.before || this.after) {
9696             
9697             inputblock = {
9698                 cls : 'input-group',
9699                 cn :  [] 
9700             };
9701             if (this.before) {
9702                 inputblock.cn.push({
9703                     tag :'span',
9704                     cls : 'input-group-addon',
9705                     html : this.before
9706                 });
9707             }
9708             
9709             inputblock.cn.push(input);
9710             
9711             if(this.hasFeedback && !this.allowBlank){
9712                 inputblock.cls += ' has-feedback';
9713                 inputblock.cn.push(feedback);
9714             }
9715             
9716             if (this.after) {
9717                 inputblock.cn.push({
9718                     tag :'span',
9719                     cls : 'input-group-addon',
9720                     html : this.after
9721                 });
9722             }
9723             
9724         }
9725         
9726         if (align ==='left' && this.fieldLabel.length) {
9727             cfg.cn = [
9728                 {
9729                     tag: 'label',
9730                     'for' :  id,
9731                     cls : 'control-label',
9732                     html : this.fieldLabel
9733                 },
9734                 {
9735                     cls : "",
9736                     cn: [
9737                         inputblock
9738                     ]
9739                 }
9740
9741             ];
9742             
9743             if(this.labelWidth > 12){
9744                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
9745             }
9746
9747             if(this.labelWidth < 13 && this.labelmd == 0){
9748                 this.labelmd = this.labelWidth;
9749             }
9750
9751             if(this.labellg > 0){
9752                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
9753                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
9754             }
9755
9756             if(this.labelmd > 0){
9757                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
9758                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
9759             }
9760
9761             if(this.labelsm > 0){
9762                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
9763                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
9764             }
9765
9766             if(this.labelxs > 0){
9767                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
9768                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
9769             }
9770             
9771         } else if ( this.fieldLabel.length) {
9772             cfg.cn = [
9773
9774                {
9775                    tag: 'label',
9776                    //cls : 'input-group-addon',
9777                    html : this.fieldLabel
9778
9779                },
9780
9781                inputblock
9782
9783            ];
9784
9785         } else {
9786
9787             cfg.cn = [
9788
9789                 inputblock
9790
9791             ];
9792                 
9793         }
9794         
9795         if (this.disabled) {
9796             input.disabled=true;
9797         }
9798         
9799         return cfg;
9800         
9801     },
9802     /**
9803      * return the real textarea element.
9804      */
9805     inputEl: function ()
9806     {
9807         return this.el.select('textarea.form-control',true).first();
9808     },
9809     
9810     /**
9811      * Clear any invalid styles/messages for this field
9812      */
9813     clearInvalid : function()
9814     {
9815         
9816         if(!this.el || this.preventMark){ // not rendered
9817             return;
9818         }
9819         
9820         var label = this.el.select('label', true).first();
9821         var icon = this.el.select('i.fa-star', true).first();
9822         
9823         if(label && icon){
9824             icon.remove();
9825         }
9826         
9827         this.el.removeClass(this.invalidClass);
9828         
9829         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9830             
9831             var feedback = this.el.select('.form-control-feedback', true).first();
9832             
9833             if(feedback){
9834                 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9835             }
9836             
9837         }
9838         
9839         this.fireEvent('valid', this);
9840     },
9841     
9842      /**
9843      * Mark this field as valid
9844      */
9845     markValid : function()
9846     {
9847         if(!this.el  || this.preventMark){ // not rendered
9848             return;
9849         }
9850         
9851         this.el.removeClass([this.invalidClass, this.validClass]);
9852         
9853         var feedback = this.el.select('.form-control-feedback', true).first();
9854             
9855         if(feedback){
9856             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9857         }
9858
9859         if(this.disabled || this.allowBlank){
9860             return;
9861         }
9862         
9863         var label = this.el.select('label', true).first();
9864         var icon = this.el.select('i.fa-star', true).first();
9865         
9866         if(label && icon){
9867             icon.remove();
9868         }
9869         
9870         this.el.addClass(this.validClass);
9871         
9872         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9873             
9874             var feedback = this.el.select('.form-control-feedback', true).first();
9875             
9876             if(feedback){
9877                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9878                 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9879             }
9880             
9881         }
9882         
9883         this.fireEvent('valid', this);
9884     },
9885     
9886      /**
9887      * Mark this field as invalid
9888      * @param {String} msg The validation message
9889      */
9890     markInvalid : function(msg)
9891     {
9892         if(!this.el  || this.preventMark){ // not rendered
9893             return;
9894         }
9895         
9896         this.el.removeClass([this.invalidClass, this.validClass]);
9897         
9898         var feedback = this.el.select('.form-control-feedback', true).first();
9899             
9900         if(feedback){
9901             this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9902         }
9903
9904         if(this.disabled || this.allowBlank){
9905             return;
9906         }
9907         
9908         var label = this.el.select('label', true).first();
9909         var icon = this.el.select('i.fa-star', true).first();
9910         
9911         if(!this.getValue().length && label && !icon){
9912             this.el.createChild({
9913                 tag : 'i',
9914                 cls : 'text-danger fa fa-lg fa-star',
9915                 tooltip : 'This field is required',
9916                 style : 'margin-right:5px;'
9917             }, label, true);
9918         }
9919
9920         this.el.addClass(this.invalidClass);
9921         
9922         if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9923             
9924             var feedback = this.el.select('.form-control-feedback', true).first();
9925             
9926             if(feedback){
9927                 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9928                 
9929                 if(this.getValue().length || this.forceFeedback){
9930                     this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9931                 }
9932                 
9933             }
9934             
9935         }
9936         
9937         this.fireEvent('invalid', this, msg);
9938     }
9939 });
9940
9941  
9942 /*
9943  * - LGPL
9944  *
9945  * trigger field - base class for combo..
9946  * 
9947  */
9948  
9949 /**
9950  * @class Roo.bootstrap.TriggerField
9951  * @extends Roo.bootstrap.Input
9952  * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
9953  * The trigger has no default action, so you must assign a function to implement the trigger click handler by
9954  * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
9955  * for which you can provide a custom implementation.  For example:
9956  * <pre><code>
9957 var trigger = new Roo.bootstrap.TriggerField();
9958 trigger.onTriggerClick = myTriggerFn;
9959 trigger.applyTo('my-field');
9960 </code></pre>
9961  *
9962  * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
9963  * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
9964  * @cfg {String} triggerClass An additional CSS class used to style the trigger button.  The trigger will always get the
9965  * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
9966  * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
9967
9968  * @constructor
9969  * Create a new TriggerField.
9970  * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
9971  * to the base TextField)
9972  */
9973 Roo.bootstrap.TriggerField = function(config){
9974     this.mimicing = false;
9975     Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
9976 };
9977
9978 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input,  {
9979     /**
9980      * @cfg {String} triggerClass A CSS class to apply to the trigger
9981      */
9982      /**
9983      * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
9984      */
9985     hideTrigger:false,
9986
9987     /**
9988      * @cfg {Boolean} removable (true|false) special filter default false
9989      */
9990     removable : false,
9991     
9992     /** @cfg {Boolean} grow @hide */
9993     /** @cfg {Number} growMin @hide */
9994     /** @cfg {Number} growMax @hide */
9995
9996     /**
9997      * @hide 
9998      * @method
9999      */
10000     autoSize: Roo.emptyFn,
10001     // private
10002     monitorTab : true,
10003     // private
10004     deferHeight : true,
10005
10006     
10007     actionMode : 'wrap',
10008     
10009     caret : false,
10010     
10011     
10012     getAutoCreate : function(){
10013        
10014         var align = this.labelAlign || this.parentLabelAlign();
10015         
10016         var id = Roo.id();
10017         
10018         var cfg = {
10019             cls: 'form-group' //input-group
10020         };
10021         
10022         
10023         var input =  {
10024             tag: 'input',
10025             id : id,
10026             type : this.inputType,
10027             cls : 'form-control',
10028             autocomplete: 'new-password',
10029             placeholder : this.placeholder || '' 
10030             
10031         };
10032         if (this.name) {
10033             input.name = this.name;
10034         }
10035         if (this.size) {
10036             input.cls += ' input-' + this.size;
10037         }
10038         
10039         if (this.disabled) {
10040             input.disabled=true;
10041         }
10042         
10043         var inputblock = input;
10044         
10045         if(this.hasFeedback && !this.allowBlank){
10046             
10047             var feedback = {
10048                 tag: 'span',
10049                 cls: 'glyphicon form-control-feedback'
10050             };
10051             
10052             if(this.removable && !this.editable && !this.tickable){
10053                 inputblock = {
10054                     cls : 'has-feedback',
10055                     cn :  [
10056                         inputblock,
10057                         {
10058                             tag: 'button',
10059                             html : 'x',
10060                             cls : 'roo-combo-removable-btn close'
10061                         },
10062                         feedback
10063                     ] 
10064                 };
10065             } else {
10066                 inputblock = {
10067                     cls : 'has-feedback',
10068                     cn :  [
10069                         inputblock,
10070                         feedback
10071                     ] 
10072                 };
10073             }
10074
10075         } else {
10076             if(this.removable && !this.editable && !this.tickable){
10077                 inputblock = {
10078                     cls : 'roo-removable',
10079                     cn :  [
10080                         inputblock,
10081                         {
10082                             tag: 'button',
10083                             html : 'x',
10084                             cls : 'roo-combo-removable-btn close'
10085                         }
10086                     ] 
10087                 };
10088             }
10089         }
10090         
10091         if (this.before || this.after) {
10092             
10093             inputblock = {
10094                 cls : 'input-group',
10095                 cn :  [] 
10096             };
10097             if (this.before) {
10098                 inputblock.cn.push({
10099                     tag :'span',
10100                     cls : 'input-group-addon',
10101                     html : this.before
10102                 });
10103             }
10104             
10105             inputblock.cn.push(input);
10106             
10107             if(this.hasFeedback && !this.allowBlank){
10108                 inputblock.cls += ' has-feedback';
10109                 inputblock.cn.push(feedback);
10110             }
10111             
10112             if (this.after) {
10113                 inputblock.cn.push({
10114                     tag :'span',
10115                     cls : 'input-group-addon',
10116                     html : this.after
10117                 });
10118             }
10119             
10120         };
10121         
10122         var box = {
10123             tag: 'div',
10124             cn: [
10125                 {
10126                     tag: 'input',
10127                     type : 'hidden',
10128                     cls: 'form-hidden-field'
10129                 },
10130                 inputblock
10131             ]
10132             
10133         };
10134         
10135         if(this.multiple){
10136             box = {
10137                 tag: 'div',
10138                 cn: [
10139                     {
10140                         tag: 'input',
10141                         type : 'hidden',
10142                         cls: 'form-hidden-field'
10143                     },
10144                     {
10145                         tag: 'ul',
10146                         cls: 'roo-select2-choices',
10147                         cn:[
10148                             {
10149                                 tag: 'li',
10150                                 cls: 'roo-select2-search-field',
10151                                 cn: [
10152
10153                                     inputblock
10154                                 ]
10155                             }
10156                         ]
10157                     }
10158                 ]
10159             }
10160         };
10161         
10162         var combobox = {
10163             cls: 'roo-select2-container input-group',
10164             cn: [
10165                 box
10166 //                {
10167 //                    tag: 'ul',
10168 //                    cls: 'typeahead typeahead-long dropdown-menu',
10169 //                    style: 'display:none'
10170 //                }
10171             ]
10172         };
10173         
10174         if(!this.multiple && this.showToggleBtn){
10175             
10176             var caret = {
10177                         tag: 'span',
10178                         cls: 'caret'
10179              };
10180             if (this.caret != false) {
10181                 caret = {
10182                      tag: 'i',
10183                      cls: 'fa fa-' + this.caret
10184                 };
10185                 
10186             }
10187             
10188             combobox.cn.push({
10189                 tag :'span',
10190                 cls : 'input-group-addon btn dropdown-toggle',
10191                 cn : [
10192                     caret,
10193                     {
10194                         tag: 'span',
10195                         cls: 'combobox-clear',
10196                         cn  : [
10197                             {
10198                                 tag : 'i',
10199                                 cls: 'icon-remove'
10200                             }
10201                         ]
10202                     }
10203                 ]
10204
10205             })
10206         }
10207         
10208         if(this.multiple){
10209             combobox.cls += ' roo-select2-container-multi';
10210         }
10211         
10212         if (align ==='left' && this.fieldLabel.length) {
10213             
10214             cfg.cls += ' roo-form-group-label-left';
10215
10216             cfg.cn = [
10217                 {
10218                     tag : 'i',
10219                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10220                     tooltip : 'This field is required'
10221                 },
10222                 {
10223                     tag: 'label',
10224                     'for' :  id,
10225                     cls : 'control-label',
10226                     html : this.fieldLabel
10227
10228                 },
10229                 {
10230                     cls : "", 
10231                     cn: [
10232                         combobox
10233                     ]
10234                 }
10235
10236             ];
10237             
10238             var labelCfg = cfg.cn[1];
10239             var contentCfg = cfg.cn[2];
10240             
10241             if(this.indicatorpos == 'right'){
10242                 cfg.cn = [
10243                     {
10244                         tag: 'label',
10245                         'for' :  id,
10246                         cls : 'control-label',
10247                         cn : [
10248                             {
10249                                 tag : 'span',
10250                                 html : this.fieldLabel
10251                             },
10252                             {
10253                                 tag : 'i',
10254                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10255                                 tooltip : 'This field is required'
10256                             }
10257                         ]
10258                     },
10259                     {
10260                         cls : "", 
10261                         cn: [
10262                             combobox
10263                         ]
10264                     }
10265
10266                 ];
10267                 
10268                 labelCfg = cfg.cn[0];
10269                 contentCfg = cfg.cn[1];
10270             }
10271             
10272             if(this.labelWidth > 12){
10273                 labelCfg.style = "width: " + this.labelWidth + 'px';
10274             }
10275             
10276             if(this.labelWidth < 13 && this.labelmd == 0){
10277                 this.labelmd = this.labelWidth;
10278             }
10279             
10280             if(this.labellg > 0){
10281                 labelCfg.cls += ' col-lg-' + this.labellg;
10282                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10283             }
10284             
10285             if(this.labelmd > 0){
10286                 labelCfg.cls += ' col-md-' + this.labelmd;
10287                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10288             }
10289             
10290             if(this.labelsm > 0){
10291                 labelCfg.cls += ' col-sm-' + this.labelsm;
10292                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10293             }
10294             
10295             if(this.labelxs > 0){
10296                 labelCfg.cls += ' col-xs-' + this.labelxs;
10297                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10298             }
10299             
10300         } else if ( this.fieldLabel.length) {
10301 //                Roo.log(" label");
10302             cfg.cn = [
10303                 {
10304                    tag : 'i',
10305                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10306                    tooltip : 'This field is required'
10307                },
10308                {
10309                    tag: 'label',
10310                    //cls : 'input-group-addon',
10311                    html : this.fieldLabel
10312
10313                },
10314
10315                combobox
10316
10317             ];
10318             
10319             if(this.indicatorpos == 'right'){
10320                 
10321                 cfg.cn = [
10322                     {
10323                        tag: 'label',
10324                        cn : [
10325                            {
10326                                tag : 'span',
10327                                html : this.fieldLabel
10328                            },
10329                            {
10330                               tag : 'i',
10331                               cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10332                               tooltip : 'This field is required'
10333                            }
10334                        ]
10335
10336                     },
10337                     combobox
10338
10339                 ];
10340
10341             }
10342
10343         } else {
10344             
10345 //                Roo.log(" no label && no align");
10346                 cfg = combobox
10347                      
10348                 
10349         }
10350         
10351         var settings=this;
10352         ['xs','sm','md','lg'].map(function(size){
10353             if (settings[size]) {
10354                 cfg.cls += ' col-' + size + '-' + settings[size];
10355             }
10356         });
10357         
10358         return cfg;
10359         
10360     },
10361     
10362     
10363     
10364     // private
10365     onResize : function(w, h){
10366 //        Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10367 //        if(typeof w == 'number'){
10368 //            var x = w - this.trigger.getWidth();
10369 //            this.inputEl().setWidth(this.adjustWidth('input', x));
10370 //            this.trigger.setStyle('left', x+'px');
10371 //        }
10372     },
10373
10374     // private
10375     adjustSize : Roo.BoxComponent.prototype.adjustSize,
10376
10377     // private
10378     getResizeEl : function(){
10379         return this.inputEl();
10380     },
10381
10382     // private
10383     getPositionEl : function(){
10384         return this.inputEl();
10385     },
10386
10387     // private
10388     alignErrorIcon : function(){
10389         this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10390     },
10391
10392     // private
10393     initEvents : function(){
10394         
10395         this.createList();
10396         
10397         Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10398         //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10399         if(!this.multiple && this.showToggleBtn){
10400             this.trigger = this.el.select('span.dropdown-toggle',true).first();
10401             if(this.hideTrigger){
10402                 this.trigger.setDisplayed(false);
10403             }
10404             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10405         }
10406         
10407         if(this.multiple){
10408             this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10409         }
10410         
10411         if(this.removable && !this.editable && !this.tickable){
10412             var close = this.closeTriggerEl();
10413             
10414             if(close){
10415                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10416                 close.on('click', this.removeBtnClick, this, close);
10417             }
10418         }
10419         
10420         //this.trigger.addClassOnOver('x-form-trigger-over');
10421         //this.trigger.addClassOnClick('x-form-trigger-click');
10422         
10423         //if(!this.width){
10424         //    this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10425         //}
10426     },
10427     
10428     closeTriggerEl : function()
10429     {
10430         var close = this.el.select('.roo-combo-removable-btn', true).first();
10431         return close ? close : false;
10432     },
10433     
10434     removeBtnClick : function(e, h, el)
10435     {
10436         e.preventDefault();
10437         
10438         if(this.fireEvent("remove", this) !== false){
10439             this.reset();
10440             this.fireEvent("afterremove", this)
10441         }
10442     },
10443     
10444     createList : function()
10445     {
10446         this.list = Roo.get(document.body).createChild({
10447             tag: 'ul',
10448             cls: 'typeahead typeahead-long dropdown-menu',
10449             style: 'display:none'
10450         });
10451         
10452         this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10453         
10454     },
10455
10456     // private
10457     initTrigger : function(){
10458        
10459     },
10460
10461     // private
10462     onDestroy : function(){
10463         if(this.trigger){
10464             this.trigger.removeAllListeners();
10465           //  this.trigger.remove();
10466         }
10467         //if(this.wrap){
10468         //    this.wrap.remove();
10469         //}
10470         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10471     },
10472
10473     // private
10474     onFocus : function(){
10475         Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10476         /*
10477         if(!this.mimicing){
10478             this.wrap.addClass('x-trigger-wrap-focus');
10479             this.mimicing = true;
10480             Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10481             if(this.monitorTab){
10482                 this.el.on("keydown", this.checkTab, this);
10483             }
10484         }
10485         */
10486     },
10487
10488     // private
10489     checkTab : function(e){
10490         if(e.getKey() == e.TAB){
10491             this.triggerBlur();
10492         }
10493     },
10494
10495     // private
10496     onBlur : function(){
10497         // do nothing
10498     },
10499
10500     // private
10501     mimicBlur : function(e, t){
10502         /*
10503         if(!this.wrap.contains(t) && this.validateBlur()){
10504             this.triggerBlur();
10505         }
10506         */
10507     },
10508
10509     // private
10510     triggerBlur : function(){
10511         this.mimicing = false;
10512         Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10513         if(this.monitorTab){
10514             this.el.un("keydown", this.checkTab, this);
10515         }
10516         //this.wrap.removeClass('x-trigger-wrap-focus');
10517         Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10518     },
10519
10520     // private
10521     // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10522     validateBlur : function(e, t){
10523         return true;
10524     },
10525
10526     // private
10527     onDisable : function(){
10528         this.inputEl().dom.disabled = true;
10529         //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10530         //if(this.wrap){
10531         //    this.wrap.addClass('x-item-disabled');
10532         //}
10533     },
10534
10535     // private
10536     onEnable : function(){
10537         this.inputEl().dom.disabled = false;
10538         //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10539         //if(this.wrap){
10540         //    this.el.removeClass('x-item-disabled');
10541         //}
10542     },
10543
10544     // private
10545     onShow : function(){
10546         var ae = this.getActionEl();
10547         
10548         if(ae){
10549             ae.dom.style.display = '';
10550             ae.dom.style.visibility = 'visible';
10551         }
10552     },
10553
10554     // private
10555     
10556     onHide : function(){
10557         var ae = this.getActionEl();
10558         ae.dom.style.display = 'none';
10559     },
10560
10561     /**
10562      * The function that should handle the trigger's click event.  This method does nothing by default until overridden
10563      * by an implementing function.
10564      * @method
10565      * @param {EventObject} e
10566      */
10567     onTriggerClick : Roo.emptyFn
10568 });
10569  /*
10570  * Based on:
10571  * Ext JS Library 1.1.1
10572  * Copyright(c) 2006-2007, Ext JS, LLC.
10573  *
10574  * Originally Released Under LGPL - original licence link has changed is not relivant.
10575  *
10576  * Fork - LGPL
10577  * <script type="text/javascript">
10578  */
10579
10580
10581 /**
10582  * @class Roo.data.SortTypes
10583  * @singleton
10584  * Defines the default sorting (casting?) comparison functions used when sorting data.
10585  */
10586 Roo.data.SortTypes = {
10587     /**
10588      * Default sort that does nothing
10589      * @param {Mixed} s The value being converted
10590      * @return {Mixed} The comparison value
10591      */
10592     none : function(s){
10593         return s;
10594     },
10595     
10596     /**
10597      * The regular expression used to strip tags
10598      * @type {RegExp}
10599      * @property
10600      */
10601     stripTagsRE : /<\/?[^>]+>/gi,
10602     
10603     /**
10604      * Strips all HTML tags to sort on text only
10605      * @param {Mixed} s The value being converted
10606      * @return {String} The comparison value
10607      */
10608     asText : function(s){
10609         return String(s).replace(this.stripTagsRE, "");
10610     },
10611     
10612     /**
10613      * Strips all HTML tags to sort on text only - Case insensitive
10614      * @param {Mixed} s The value being converted
10615      * @return {String} The comparison value
10616      */
10617     asUCText : function(s){
10618         return String(s).toUpperCase().replace(this.stripTagsRE, "");
10619     },
10620     
10621     /**
10622      * Case insensitive string
10623      * @param {Mixed} s The value being converted
10624      * @return {String} The comparison value
10625      */
10626     asUCString : function(s) {
10627         return String(s).toUpperCase();
10628     },
10629     
10630     /**
10631      * Date sorting
10632      * @param {Mixed} s The value being converted
10633      * @return {Number} The comparison value
10634      */
10635     asDate : function(s) {
10636         if(!s){
10637             return 0;
10638         }
10639         if(s instanceof Date){
10640             return s.getTime();
10641         }
10642         return Date.parse(String(s));
10643     },
10644     
10645     /**
10646      * Float sorting
10647      * @param {Mixed} s The value being converted
10648      * @return {Float} The comparison value
10649      */
10650     asFloat : function(s) {
10651         var val = parseFloat(String(s).replace(/,/g, ""));
10652         if(isNaN(val)) {
10653             val = 0;
10654         }
10655         return val;
10656     },
10657     
10658     /**
10659      * Integer sorting
10660      * @param {Mixed} s The value being converted
10661      * @return {Number} The comparison value
10662      */
10663     asInt : function(s) {
10664         var val = parseInt(String(s).replace(/,/g, ""));
10665         if(isNaN(val)) {
10666             val = 0;
10667         }
10668         return val;
10669     }
10670 };/*
10671  * Based on:
10672  * Ext JS Library 1.1.1
10673  * Copyright(c) 2006-2007, Ext JS, LLC.
10674  *
10675  * Originally Released Under LGPL - original licence link has changed is not relivant.
10676  *
10677  * Fork - LGPL
10678  * <script type="text/javascript">
10679  */
10680
10681 /**
10682 * @class Roo.data.Record
10683  * Instances of this class encapsulate both record <em>definition</em> information, and record
10684  * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10685  * to access Records cached in an {@link Roo.data.Store} object.<br>
10686  * <p>
10687  * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10688  * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10689  * objects.<br>
10690  * <p>
10691  * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10692  * @constructor
10693  * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10694  * {@link #create}. The parameters are the same.
10695  * @param {Array} data An associative Array of data values keyed by the field name.
10696  * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10697  * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10698  * not specified an integer id is generated.
10699  */
10700 Roo.data.Record = function(data, id){
10701     this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10702     this.data = data;
10703 };
10704
10705 /**
10706  * Generate a constructor for a specific record layout.
10707  * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10708  * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10709  * Each field definition object may contain the following properties: <ul>
10710  * <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,
10711  * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10712  * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10713  * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10714  * is being used, then this is a string containing the javascript expression to reference the data relative to 
10715  * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10716  * to the data item relative to the record element. If the mapping expression is the same as the field name,
10717  * this may be omitted.</p></li>
10718  * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10719  * <ul><li>auto (Default, implies no conversion)</li>
10720  * <li>string</li>
10721  * <li>int</li>
10722  * <li>float</li>
10723  * <li>boolean</li>
10724  * <li>date</li></ul></p></li>
10725  * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10726  * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10727  * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10728  * by the Reader into an object that will be stored in the Record. It is passed the
10729  * following parameters:<ul>
10730  * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10731  * </ul></p></li>
10732  * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
10733  * </ul>
10734  * <br>usage:<br><pre><code>
10735 var TopicRecord = Roo.data.Record.create(
10736     {name: 'title', mapping: 'topic_title'},
10737     {name: 'author', mapping: 'username'},
10738     {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
10739     {name: 'lastPost', mapping: 'post_time', type: 'date'},
10740     {name: 'lastPoster', mapping: 'user2'},
10741     {name: 'excerpt', mapping: 'post_text'}
10742 );
10743
10744 var myNewRecord = new TopicRecord({
10745     title: 'Do my job please',
10746     author: 'noobie',
10747     totalPosts: 1,
10748     lastPost: new Date(),
10749     lastPoster: 'Animal',
10750     excerpt: 'No way dude!'
10751 });
10752 myStore.add(myNewRecord);
10753 </code></pre>
10754  * @method create
10755  * @static
10756  */
10757 Roo.data.Record.create = function(o){
10758     var f = function(){
10759         f.superclass.constructor.apply(this, arguments);
10760     };
10761     Roo.extend(f, Roo.data.Record);
10762     var p = f.prototype;
10763     p.fields = new Roo.util.MixedCollection(false, function(field){
10764         return field.name;
10765     });
10766     for(var i = 0, len = o.length; i < len; i++){
10767         p.fields.add(new Roo.data.Field(o[i]));
10768     }
10769     f.getField = function(name){
10770         return p.fields.get(name);  
10771     };
10772     return f;
10773 };
10774
10775 Roo.data.Record.AUTO_ID = 1000;
10776 Roo.data.Record.EDIT = 'edit';
10777 Roo.data.Record.REJECT = 'reject';
10778 Roo.data.Record.COMMIT = 'commit';
10779
10780 Roo.data.Record.prototype = {
10781     /**
10782      * Readonly flag - true if this record has been modified.
10783      * @type Boolean
10784      */
10785     dirty : false,
10786     editing : false,
10787     error: null,
10788     modified: null,
10789
10790     // private
10791     join : function(store){
10792         this.store = store;
10793     },
10794
10795     /**
10796      * Set the named field to the specified value.
10797      * @param {String} name The name of the field to set.
10798      * @param {Object} value The value to set the field to.
10799      */
10800     set : function(name, value){
10801         if(this.data[name] == value){
10802             return;
10803         }
10804         this.dirty = true;
10805         if(!this.modified){
10806             this.modified = {};
10807         }
10808         if(typeof this.modified[name] == 'undefined'){
10809             this.modified[name] = this.data[name];
10810         }
10811         this.data[name] = value;
10812         if(!this.editing && this.store){
10813             this.store.afterEdit(this);
10814         }       
10815     },
10816
10817     /**
10818      * Get the value of the named field.
10819      * @param {String} name The name of the field to get the value of.
10820      * @return {Object} The value of the field.
10821      */
10822     get : function(name){
10823         return this.data[name]; 
10824     },
10825
10826     // private
10827     beginEdit : function(){
10828         this.editing = true;
10829         this.modified = {}; 
10830     },
10831
10832     // private
10833     cancelEdit : function(){
10834         this.editing = false;
10835         delete this.modified;
10836     },
10837
10838     // private
10839     endEdit : function(){
10840         this.editing = false;
10841         if(this.dirty && this.store){
10842             this.store.afterEdit(this);
10843         }
10844     },
10845
10846     /**
10847      * Usually called by the {@link Roo.data.Store} which owns the Record.
10848      * Rejects all changes made to the Record since either creation, or the last commit operation.
10849      * Modified fields are reverted to their original values.
10850      * <p>
10851      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10852      * of reject operations.
10853      */
10854     reject : function(){
10855         var m = this.modified;
10856         for(var n in m){
10857             if(typeof m[n] != "function"){
10858                 this.data[n] = m[n];
10859             }
10860         }
10861         this.dirty = false;
10862         delete this.modified;
10863         this.editing = false;
10864         if(this.store){
10865             this.store.afterReject(this);
10866         }
10867     },
10868
10869     /**
10870      * Usually called by the {@link Roo.data.Store} which owns the Record.
10871      * Commits all changes made to the Record since either creation, or the last commit operation.
10872      * <p>
10873      * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
10874      * of commit operations.
10875      */
10876     commit : function(){
10877         this.dirty = false;
10878         delete this.modified;
10879         this.editing = false;
10880         if(this.store){
10881             this.store.afterCommit(this);
10882         }
10883     },
10884
10885     // private
10886     hasError : function(){
10887         return this.error != null;
10888     },
10889
10890     // private
10891     clearError : function(){
10892         this.error = null;
10893     },
10894
10895     /**
10896      * Creates a copy of this record.
10897      * @param {String} id (optional) A new record id if you don't want to use this record's id
10898      * @return {Record}
10899      */
10900     copy : function(newId) {
10901         return new this.constructor(Roo.apply({}, this.data), newId || this.id);
10902     }
10903 };/*
10904  * Based on:
10905  * Ext JS Library 1.1.1
10906  * Copyright(c) 2006-2007, Ext JS, LLC.
10907  *
10908  * Originally Released Under LGPL - original licence link has changed is not relivant.
10909  *
10910  * Fork - LGPL
10911  * <script type="text/javascript">
10912  */
10913
10914
10915
10916 /**
10917  * @class Roo.data.Store
10918  * @extends Roo.util.Observable
10919  * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
10920  * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
10921  * <p>
10922  * 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
10923  * has no knowledge of the format of the data returned by the Proxy.<br>
10924  * <p>
10925  * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
10926  * instances from the data object. These records are cached and made available through accessor functions.
10927  * @constructor
10928  * Creates a new Store.
10929  * @param {Object} config A config object containing the objects needed for the Store to access data,
10930  * and read the data into Records.
10931  */
10932 Roo.data.Store = function(config){
10933     this.data = new Roo.util.MixedCollection(false);
10934     this.data.getKey = function(o){
10935         return o.id;
10936     };
10937     this.baseParams = {};
10938     // private
10939     this.paramNames = {
10940         "start" : "start",
10941         "limit" : "limit",
10942         "sort" : "sort",
10943         "dir" : "dir",
10944         "multisort" : "_multisort"
10945     };
10946
10947     if(config && config.data){
10948         this.inlineData = config.data;
10949         delete config.data;
10950     }
10951
10952     Roo.apply(this, config);
10953     
10954     if(this.reader){ // reader passed
10955         this.reader = Roo.factory(this.reader, Roo.data);
10956         this.reader.xmodule = this.xmodule || false;
10957         if(!this.recordType){
10958             this.recordType = this.reader.recordType;
10959         }
10960         if(this.reader.onMetaChange){
10961             this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
10962         }
10963     }
10964
10965     if(this.recordType){
10966         this.fields = this.recordType.prototype.fields;
10967     }
10968     this.modified = [];
10969
10970     this.addEvents({
10971         /**
10972          * @event datachanged
10973          * Fires when the data cache has changed, and a widget which is using this Store
10974          * as a Record cache should refresh its view.
10975          * @param {Store} this
10976          */
10977         datachanged : true,
10978         /**
10979          * @event metachange
10980          * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
10981          * @param {Store} this
10982          * @param {Object} meta The JSON metadata
10983          */
10984         metachange : true,
10985         /**
10986          * @event add
10987          * Fires when Records have been added to the Store
10988          * @param {Store} this
10989          * @param {Roo.data.Record[]} records The array of Records added
10990          * @param {Number} index The index at which the record(s) were added
10991          */
10992         add : true,
10993         /**
10994          * @event remove
10995          * Fires when a Record has been removed from the Store
10996          * @param {Store} this
10997          * @param {Roo.data.Record} record The Record that was removed
10998          * @param {Number} index The index at which the record was removed
10999          */
11000         remove : true,
11001         /**
11002          * @event update
11003          * Fires when a Record has been updated
11004          * @param {Store} this
11005          * @param {Roo.data.Record} record The Record that was updated
11006          * @param {String} operation The update operation being performed.  Value may be one of:
11007          * <pre><code>
11008  Roo.data.Record.EDIT
11009  Roo.data.Record.REJECT
11010  Roo.data.Record.COMMIT
11011          * </code></pre>
11012          */
11013         update : true,
11014         /**
11015          * @event clear
11016          * Fires when the data cache has been cleared.
11017          * @param {Store} this
11018          */
11019         clear : true,
11020         /**
11021          * @event beforeload
11022          * Fires before a request is made for a new data object.  If the beforeload handler returns false
11023          * the load action will be canceled.
11024          * @param {Store} this
11025          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11026          */
11027         beforeload : true,
11028         /**
11029          * @event beforeloadadd
11030          * Fires after a new set of Records has been loaded.
11031          * @param {Store} this
11032          * @param {Roo.data.Record[]} records The Records that were loaded
11033          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11034          */
11035         beforeloadadd : true,
11036         /**
11037          * @event load
11038          * Fires after a new set of Records has been loaded, before they are added to the store.
11039          * @param {Store} this
11040          * @param {Roo.data.Record[]} records The Records that were loaded
11041          * @param {Object} options The loading options that were specified (see {@link #load} for details)
11042          * @params {Object} return from reader
11043          */
11044         load : true,
11045         /**
11046          * @event loadexception
11047          * Fires if an exception occurs in the Proxy during loading.
11048          * Called with the signature of the Proxy's "loadexception" event.
11049          * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11050          * 
11051          * @param {Proxy} 
11052          * @param {Object} return from JsonData.reader() - success, totalRecords, records
11053          * @param {Object} load options 
11054          * @param {Object} jsonData from your request (normally this contains the Exception)
11055          */
11056         loadexception : true
11057     });
11058     
11059     if(this.proxy){
11060         this.proxy = Roo.factory(this.proxy, Roo.data);
11061         this.proxy.xmodule = this.xmodule || false;
11062         this.relayEvents(this.proxy,  ["loadexception"]);
11063     }
11064     this.sortToggle = {};
11065     this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11066
11067     Roo.data.Store.superclass.constructor.call(this);
11068
11069     if(this.inlineData){
11070         this.loadData(this.inlineData);
11071         delete this.inlineData;
11072     }
11073 };
11074
11075 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11076      /**
11077     * @cfg {boolean} isLocal   flag if data is locally available (and can be always looked up
11078     * without a remote query - used by combo/forms at present.
11079     */
11080     
11081     /**
11082     * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11083     */
11084     /**
11085     * @cfg {Array} data Inline data to be loaded when the store is initialized.
11086     */
11087     /**
11088     * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11089     * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11090     */
11091     /**
11092     * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11093     * on any HTTP request
11094     */
11095     /**
11096     * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11097     */
11098     /**
11099     * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11100     */
11101     multiSort: false,
11102     /**
11103     * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11104     * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11105     */
11106     remoteSort : false,
11107
11108     /**
11109     * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11110      * loaded or when a record is removed. (defaults to false).
11111     */
11112     pruneModifiedRecords : false,
11113
11114     // private
11115     lastOptions : null,
11116
11117     /**
11118      * Add Records to the Store and fires the add event.
11119      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11120      */
11121     add : function(records){
11122         records = [].concat(records);
11123         for(var i = 0, len = records.length; i < len; i++){
11124             records[i].join(this);
11125         }
11126         var index = this.data.length;
11127         this.data.addAll(records);
11128         this.fireEvent("add", this, records, index);
11129     },
11130
11131     /**
11132      * Remove a Record from the Store and fires the remove event.
11133      * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11134      */
11135     remove : function(record){
11136         var index = this.data.indexOf(record);
11137         this.data.removeAt(index);
11138  
11139         if(this.pruneModifiedRecords){
11140             this.modified.remove(record);
11141         }
11142         this.fireEvent("remove", this, record, index);
11143     },
11144
11145     /**
11146      * Remove all Records from the Store and fires the clear event.
11147      */
11148     removeAll : function(){
11149         this.data.clear();
11150         if(this.pruneModifiedRecords){
11151             this.modified = [];
11152         }
11153         this.fireEvent("clear", this);
11154     },
11155
11156     /**
11157      * Inserts Records to the Store at the given index and fires the add event.
11158      * @param {Number} index The start index at which to insert the passed Records.
11159      * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11160      */
11161     insert : function(index, records){
11162         records = [].concat(records);
11163         for(var i = 0, len = records.length; i < len; i++){
11164             this.data.insert(index, records[i]);
11165             records[i].join(this);
11166         }
11167         this.fireEvent("add", this, records, index);
11168     },
11169
11170     /**
11171      * Get the index within the cache of the passed Record.
11172      * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11173      * @return {Number} The index of the passed Record. Returns -1 if not found.
11174      */
11175     indexOf : function(record){
11176         return this.data.indexOf(record);
11177     },
11178
11179     /**
11180      * Get the index within the cache of the Record with the passed id.
11181      * @param {String} id The id of the Record to find.
11182      * @return {Number} The index of the Record. Returns -1 if not found.
11183      */
11184     indexOfId : function(id){
11185         return this.data.indexOfKey(id);
11186     },
11187
11188     /**
11189      * Get the Record with the specified id.
11190      * @param {String} id The id of the Record to find.
11191      * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11192      */
11193     getById : function(id){
11194         return this.data.key(id);
11195     },
11196
11197     /**
11198      * Get the Record at the specified index.
11199      * @param {Number} index The index of the Record to find.
11200      * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11201      */
11202     getAt : function(index){
11203         return this.data.itemAt(index);
11204     },
11205
11206     /**
11207      * Returns a range of Records between specified indices.
11208      * @param {Number} startIndex (optional) The starting index (defaults to 0)
11209      * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11210      * @return {Roo.data.Record[]} An array of Records
11211      */
11212     getRange : function(start, end){
11213         return this.data.getRange(start, end);
11214     },
11215
11216     // private
11217     storeOptions : function(o){
11218         o = Roo.apply({}, o);
11219         delete o.callback;
11220         delete o.scope;
11221         this.lastOptions = o;
11222     },
11223
11224     /**
11225      * Loads the Record cache from the configured Proxy using the configured Reader.
11226      * <p>
11227      * If using remote paging, then the first load call must specify the <em>start</em>
11228      * and <em>limit</em> properties in the options.params property to establish the initial
11229      * position within the dataset, and the number of Records to cache on each read from the Proxy.
11230      * <p>
11231      * <strong>It is important to note that for remote data sources, loading is asynchronous,
11232      * and this call will return before the new data has been loaded. Perform any post-processing
11233      * in a callback function, or in a "load" event handler.</strong>
11234      * <p>
11235      * @param {Object} options An object containing properties which control loading options:<ul>
11236      * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11237      * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11238      * passed the following arguments:<ul>
11239      * <li>r : Roo.data.Record[]</li>
11240      * <li>options: Options object from the load call</li>
11241      * <li>success: Boolean success indicator</li></ul></li>
11242      * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11243      * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11244      * </ul>
11245      */
11246     load : function(options){
11247         options = options || {};
11248         if(this.fireEvent("beforeload", this, options) !== false){
11249             this.storeOptions(options);
11250             var p = Roo.apply(options.params || {}, this.baseParams);
11251             // if meta was not loaded from remote source.. try requesting it.
11252             if (!this.reader.metaFromRemote) {
11253                 p._requestMeta = 1;
11254             }
11255             if(this.sortInfo && this.remoteSort){
11256                 var pn = this.paramNames;
11257                 p[pn["sort"]] = this.sortInfo.field;
11258                 p[pn["dir"]] = this.sortInfo.direction;
11259             }
11260             if (this.multiSort) {
11261                 var pn = this.paramNames;
11262                 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11263             }
11264             
11265             this.proxy.load(p, this.reader, this.loadRecords, this, options);
11266         }
11267     },
11268
11269     /**
11270      * Reloads the Record cache from the configured Proxy using the configured Reader and
11271      * the options from the last load operation performed.
11272      * @param {Object} options (optional) An object containing properties which may override the options
11273      * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11274      * the most recently used options are reused).
11275      */
11276     reload : function(options){
11277         this.load(Roo.applyIf(options||{}, this.lastOptions));
11278     },
11279
11280     // private
11281     // Called as a callback by the Reader during a load operation.
11282     loadRecords : function(o, options, success){
11283         if(!o || success === false){
11284             if(success !== false){
11285                 this.fireEvent("load", this, [], options, o);
11286             }
11287             if(options.callback){
11288                 options.callback.call(options.scope || this, [], options, false);
11289             }
11290             return;
11291         }
11292         // if data returned failure - throw an exception.
11293         if (o.success === false) {
11294             // show a message if no listener is registered.
11295             if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11296                     Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11297             }
11298             // loadmask wil be hooked into this..
11299             this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11300             return;
11301         }
11302         var r = o.records, t = o.totalRecords || r.length;
11303         
11304         this.fireEvent("beforeloadadd", this, r, options, o);
11305         
11306         if(!options || options.add !== true){
11307             if(this.pruneModifiedRecords){
11308                 this.modified = [];
11309             }
11310             for(var i = 0, len = r.length; i < len; i++){
11311                 r[i].join(this);
11312             }
11313             if(this.snapshot){
11314                 this.data = this.snapshot;
11315                 delete this.snapshot;
11316             }
11317             this.data.clear();
11318             this.data.addAll(r);
11319             this.totalLength = t;
11320             this.applySort();
11321             this.fireEvent("datachanged", this);
11322         }else{
11323             this.totalLength = Math.max(t, this.data.length+r.length);
11324             this.add(r);
11325         }
11326         
11327         if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11328                 
11329             var e = new Roo.data.Record({});
11330
11331             e.set(this.parent.displayField, this.parent.emptyTitle);
11332             e.set(this.parent.valueField, '');
11333
11334             this.insert(0, e);
11335         }
11336             
11337         this.fireEvent("load", this, r, options, o);
11338         if(options.callback){
11339             options.callback.call(options.scope || this, r, options, true);
11340         }
11341     },
11342
11343
11344     /**
11345      * Loads data from a passed data block. A Reader which understands the format of the data
11346      * must have been configured in the constructor.
11347      * @param {Object} data The data block from which to read the Records.  The format of the data expected
11348      * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11349      * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11350      */
11351     loadData : function(o, append){
11352         var r = this.reader.readRecords(o);
11353         this.loadRecords(r, {add: append}, true);
11354     },
11355
11356     /**
11357      * Gets the number of cached records.
11358      * <p>
11359      * <em>If using paging, this may not be the total size of the dataset. If the data object
11360      * used by the Reader contains the dataset size, then the getTotalCount() function returns
11361      * the data set size</em>
11362      */
11363     getCount : function(){
11364         return this.data.length || 0;
11365     },
11366
11367     /**
11368      * Gets the total number of records in the dataset as returned by the server.
11369      * <p>
11370      * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11371      * the dataset size</em>
11372      */
11373     getTotalCount : function(){
11374         return this.totalLength || 0;
11375     },
11376
11377     /**
11378      * Returns the sort state of the Store as an object with two properties:
11379      * <pre><code>
11380  field {String} The name of the field by which the Records are sorted
11381  direction {String} The sort order, "ASC" or "DESC"
11382      * </code></pre>
11383      */
11384     getSortState : function(){
11385         return this.sortInfo;
11386     },
11387
11388     // private
11389     applySort : function(){
11390         if(this.sortInfo && !this.remoteSort){
11391             var s = this.sortInfo, f = s.field;
11392             var st = this.fields.get(f).sortType;
11393             var fn = function(r1, r2){
11394                 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11395                 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11396             };
11397             this.data.sort(s.direction, fn);
11398             if(this.snapshot && this.snapshot != this.data){
11399                 this.snapshot.sort(s.direction, fn);
11400             }
11401         }
11402     },
11403
11404     /**
11405      * Sets the default sort column and order to be used by the next load operation.
11406      * @param {String} fieldName The name of the field to sort by.
11407      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11408      */
11409     setDefaultSort : function(field, dir){
11410         this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11411     },
11412
11413     /**
11414      * Sort the Records.
11415      * If remote sorting is used, the sort is performed on the server, and the cache is
11416      * reloaded. If local sorting is used, the cache is sorted internally.
11417      * @param {String} fieldName The name of the field to sort by.
11418      * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11419      */
11420     sort : function(fieldName, dir){
11421         var f = this.fields.get(fieldName);
11422         if(!dir){
11423             this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11424             
11425             if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11426                 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11427             }else{
11428                 dir = f.sortDir;
11429             }
11430         }
11431         this.sortToggle[f.name] = dir;
11432         this.sortInfo = {field: f.name, direction: dir};
11433         if(!this.remoteSort){
11434             this.applySort();
11435             this.fireEvent("datachanged", this);
11436         }else{
11437             this.load(this.lastOptions);
11438         }
11439     },
11440
11441     /**
11442      * Calls the specified function for each of the Records in the cache.
11443      * @param {Function} fn The function to call. The Record is passed as the first parameter.
11444      * Returning <em>false</em> aborts and exits the iteration.
11445      * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11446      */
11447     each : function(fn, scope){
11448         this.data.each(fn, scope);
11449     },
11450
11451     /**
11452      * Gets all records modified since the last commit.  Modified records are persisted across load operations
11453      * (e.g., during paging).
11454      * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11455      */
11456     getModifiedRecords : function(){
11457         return this.modified;
11458     },
11459
11460     // private
11461     createFilterFn : function(property, value, anyMatch){
11462         if(!value.exec){ // not a regex
11463             value = String(value);
11464             if(value.length == 0){
11465                 return false;
11466             }
11467             value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11468         }
11469         return function(r){
11470             return value.test(r.data[property]);
11471         };
11472     },
11473
11474     /**
11475      * Sums the value of <i>property</i> for each record between start and end and returns the result.
11476      * @param {String} property A field on your records
11477      * @param {Number} start The record index to start at (defaults to 0)
11478      * @param {Number} end The last record index to include (defaults to length - 1)
11479      * @return {Number} The sum
11480      */
11481     sum : function(property, start, end){
11482         var rs = this.data.items, v = 0;
11483         start = start || 0;
11484         end = (end || end === 0) ? end : rs.length-1;
11485
11486         for(var i = start; i <= end; i++){
11487             v += (rs[i].data[property] || 0);
11488         }
11489         return v;
11490     },
11491
11492     /**
11493      * Filter the records by a specified property.
11494      * @param {String} field A field on your records
11495      * @param {String/RegExp} value Either a string that the field
11496      * should start with or a RegExp to test against the field
11497      * @param {Boolean} anyMatch True to match any part not just the beginning
11498      */
11499     filter : function(property, value, anyMatch){
11500         var fn = this.createFilterFn(property, value, anyMatch);
11501         return fn ? this.filterBy(fn) : this.clearFilter();
11502     },
11503
11504     /**
11505      * Filter by a function. The specified function will be called with each
11506      * record in this data source. If the function returns true the record is included,
11507      * otherwise it is filtered.
11508      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11509      * @param {Object} scope (optional) The scope of the function (defaults to this)
11510      */
11511     filterBy : function(fn, scope){
11512         this.snapshot = this.snapshot || this.data;
11513         this.data = this.queryBy(fn, scope||this);
11514         this.fireEvent("datachanged", this);
11515     },
11516
11517     /**
11518      * Query the records by a specified property.
11519      * @param {String} field A field on your records
11520      * @param {String/RegExp} value Either a string that the field
11521      * should start with or a RegExp to test against the field
11522      * @param {Boolean} anyMatch True to match any part not just the beginning
11523      * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11524      */
11525     query : function(property, value, anyMatch){
11526         var fn = this.createFilterFn(property, value, anyMatch);
11527         return fn ? this.queryBy(fn) : this.data.clone();
11528     },
11529
11530     /**
11531      * Query by a function. The specified function will be called with each
11532      * record in this data source. If the function returns true the record is included
11533      * in the results.
11534      * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11535      * @param {Object} scope (optional) The scope of the function (defaults to this)
11536       @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11537      **/
11538     queryBy : function(fn, scope){
11539         var data = this.snapshot || this.data;
11540         return data.filterBy(fn, scope||this);
11541     },
11542
11543     /**
11544      * Collects unique values for a particular dataIndex from this store.
11545      * @param {String} dataIndex The property to collect
11546      * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11547      * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11548      * @return {Array} An array of the unique values
11549      **/
11550     collect : function(dataIndex, allowNull, bypassFilter){
11551         var d = (bypassFilter === true && this.snapshot) ?
11552                 this.snapshot.items : this.data.items;
11553         var v, sv, r = [], l = {};
11554         for(var i = 0, len = d.length; i < len; i++){
11555             v = d[i].data[dataIndex];
11556             sv = String(v);
11557             if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11558                 l[sv] = true;
11559                 r[r.length] = v;
11560             }
11561         }
11562         return r;
11563     },
11564
11565     /**
11566      * Revert to a view of the Record cache with no filtering applied.
11567      * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11568      */
11569     clearFilter : function(suppressEvent){
11570         if(this.snapshot && this.snapshot != this.data){
11571             this.data = this.snapshot;
11572             delete this.snapshot;
11573             if(suppressEvent !== true){
11574                 this.fireEvent("datachanged", this);
11575             }
11576         }
11577     },
11578
11579     // private
11580     afterEdit : function(record){
11581         if(this.modified.indexOf(record) == -1){
11582             this.modified.push(record);
11583         }
11584         this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11585     },
11586     
11587     // private
11588     afterReject : function(record){
11589         this.modified.remove(record);
11590         this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11591     },
11592
11593     // private
11594     afterCommit : function(record){
11595         this.modified.remove(record);
11596         this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11597     },
11598
11599     /**
11600      * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11601      * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11602      */
11603     commitChanges : function(){
11604         var m = this.modified.slice(0);
11605         this.modified = [];
11606         for(var i = 0, len = m.length; i < len; i++){
11607             m[i].commit();
11608         }
11609     },
11610
11611     /**
11612      * Cancel outstanding changes on all changed records.
11613      */
11614     rejectChanges : function(){
11615         var m = this.modified.slice(0);
11616         this.modified = [];
11617         for(var i = 0, len = m.length; i < len; i++){
11618             m[i].reject();
11619         }
11620     },
11621
11622     onMetaChange : function(meta, rtype, o){
11623         this.recordType = rtype;
11624         this.fields = rtype.prototype.fields;
11625         delete this.snapshot;
11626         this.sortInfo = meta.sortInfo || this.sortInfo;
11627         this.modified = [];
11628         this.fireEvent('metachange', this, this.reader.meta);
11629     },
11630     
11631     moveIndex : function(data, type)
11632     {
11633         var index = this.indexOf(data);
11634         
11635         var newIndex = index + type;
11636         
11637         this.remove(data);
11638         
11639         this.insert(newIndex, data);
11640         
11641     }
11642 });/*
11643  * Based on:
11644  * Ext JS Library 1.1.1
11645  * Copyright(c) 2006-2007, Ext JS, LLC.
11646  *
11647  * Originally Released Under LGPL - original licence link has changed is not relivant.
11648  *
11649  * Fork - LGPL
11650  * <script type="text/javascript">
11651  */
11652
11653 /**
11654  * @class Roo.data.SimpleStore
11655  * @extends Roo.data.Store
11656  * Small helper class to make creating Stores from Array data easier.
11657  * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11658  * @cfg {Array} fields An array of field definition objects, or field name strings.
11659  * @cfg {Array} data The multi-dimensional array of data
11660  * @constructor
11661  * @param {Object} config
11662  */
11663 Roo.data.SimpleStore = function(config){
11664     Roo.data.SimpleStore.superclass.constructor.call(this, {
11665         isLocal : true,
11666         reader: new Roo.data.ArrayReader({
11667                 id: config.id
11668             },
11669             Roo.data.Record.create(config.fields)
11670         ),
11671         proxy : new Roo.data.MemoryProxy(config.data)
11672     });
11673     this.load();
11674 };
11675 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11676  * Based on:
11677  * Ext JS Library 1.1.1
11678  * Copyright(c) 2006-2007, Ext JS, LLC.
11679  *
11680  * Originally Released Under LGPL - original licence link has changed is not relivant.
11681  *
11682  * Fork - LGPL
11683  * <script type="text/javascript">
11684  */
11685
11686 /**
11687 /**
11688  * @extends Roo.data.Store
11689  * @class Roo.data.JsonStore
11690  * Small helper class to make creating Stores for JSON data easier. <br/>
11691 <pre><code>
11692 var store = new Roo.data.JsonStore({
11693     url: 'get-images.php',
11694     root: 'images',
11695     fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11696 });
11697 </code></pre>
11698  * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11699  * JsonReader and HttpProxy (unless inline data is provided).</b>
11700  * @cfg {Array} fields An array of field definition objects, or field name strings.
11701  * @constructor
11702  * @param {Object} config
11703  */
11704 Roo.data.JsonStore = function(c){
11705     Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11706         proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11707         reader: new Roo.data.JsonReader(c, c.fields)
11708     }));
11709 };
11710 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11711  * Based on:
11712  * Ext JS Library 1.1.1
11713  * Copyright(c) 2006-2007, Ext JS, LLC.
11714  *
11715  * Originally Released Under LGPL - original licence link has changed is not relivant.
11716  *
11717  * Fork - LGPL
11718  * <script type="text/javascript">
11719  */
11720
11721  
11722 Roo.data.Field = function(config){
11723     if(typeof config == "string"){
11724         config = {name: config};
11725     }
11726     Roo.apply(this, config);
11727     
11728     if(!this.type){
11729         this.type = "auto";
11730     }
11731     
11732     var st = Roo.data.SortTypes;
11733     // named sortTypes are supported, here we look them up
11734     if(typeof this.sortType == "string"){
11735         this.sortType = st[this.sortType];
11736     }
11737     
11738     // set default sortType for strings and dates
11739     if(!this.sortType){
11740         switch(this.type){
11741             case "string":
11742                 this.sortType = st.asUCString;
11743                 break;
11744             case "date":
11745                 this.sortType = st.asDate;
11746                 break;
11747             default:
11748                 this.sortType = st.none;
11749         }
11750     }
11751
11752     // define once
11753     var stripRe = /[\$,%]/g;
11754
11755     // prebuilt conversion function for this field, instead of
11756     // switching every time we're reading a value
11757     if(!this.convert){
11758         var cv, dateFormat = this.dateFormat;
11759         switch(this.type){
11760             case "":
11761             case "auto":
11762             case undefined:
11763                 cv = function(v){ return v; };
11764                 break;
11765             case "string":
11766                 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
11767                 break;
11768             case "int":
11769                 cv = function(v){
11770                     return v !== undefined && v !== null && v !== '' ?
11771                            parseInt(String(v).replace(stripRe, ""), 10) : '';
11772                     };
11773                 break;
11774             case "float":
11775                 cv = function(v){
11776                     return v !== undefined && v !== null && v !== '' ?
11777                            parseFloat(String(v).replace(stripRe, ""), 10) : ''; 
11778                     };
11779                 break;
11780             case "bool":
11781             case "boolean":
11782                 cv = function(v){ return v === true || v === "true" || v == 1; };
11783                 break;
11784             case "date":
11785                 cv = function(v){
11786                     if(!v){
11787                         return '';
11788                     }
11789                     if(v instanceof Date){
11790                         return v;
11791                     }
11792                     if(dateFormat){
11793                         if(dateFormat == "timestamp"){
11794                             return new Date(v*1000);
11795                         }
11796                         return Date.parseDate(v, dateFormat);
11797                     }
11798                     var parsed = Date.parse(v);
11799                     return parsed ? new Date(parsed) : null;
11800                 };
11801              break;
11802             
11803         }
11804         this.convert = cv;
11805     }
11806 };
11807
11808 Roo.data.Field.prototype = {
11809     dateFormat: null,
11810     defaultValue: "",
11811     mapping: null,
11812     sortType : null,
11813     sortDir : "ASC"
11814 };/*
11815  * Based on:
11816  * Ext JS Library 1.1.1
11817  * Copyright(c) 2006-2007, Ext JS, LLC.
11818  *
11819  * Originally Released Under LGPL - original licence link has changed is not relivant.
11820  *
11821  * Fork - LGPL
11822  * <script type="text/javascript">
11823  */
11824  
11825 // Base class for reading structured data from a data source.  This class is intended to be
11826 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
11827
11828 /**
11829  * @class Roo.data.DataReader
11830  * Base class for reading structured data from a data source.  This class is intended to be
11831  * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
11832  */
11833
11834 Roo.data.DataReader = function(meta, recordType){
11835     
11836     this.meta = meta;
11837     
11838     this.recordType = recordType instanceof Array ? 
11839         Roo.data.Record.create(recordType) : recordType;
11840 };
11841
11842 Roo.data.DataReader.prototype = {
11843      /**
11844      * Create an empty record
11845      * @param {Object} data (optional) - overlay some values
11846      * @return {Roo.data.Record} record created.
11847      */
11848     newRow :  function(d) {
11849         var da =  {};
11850         this.recordType.prototype.fields.each(function(c) {
11851             switch( c.type) {
11852                 case 'int' : da[c.name] = 0; break;
11853                 case 'date' : da[c.name] = new Date(); break;
11854                 case 'float' : da[c.name] = 0.0; break;
11855                 case 'boolean' : da[c.name] = false; break;
11856                 default : da[c.name] = ""; break;
11857             }
11858             
11859         });
11860         return new this.recordType(Roo.apply(da, d));
11861     }
11862     
11863 };/*
11864  * Based on:
11865  * Ext JS Library 1.1.1
11866  * Copyright(c) 2006-2007, Ext JS, LLC.
11867  *
11868  * Originally Released Under LGPL - original licence link has changed is not relivant.
11869  *
11870  * Fork - LGPL
11871  * <script type="text/javascript">
11872  */
11873
11874 /**
11875  * @class Roo.data.DataProxy
11876  * @extends Roo.data.Observable
11877  * This class is an abstract base class for implementations which provide retrieval of
11878  * unformatted data objects.<br>
11879  * <p>
11880  * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
11881  * (of the appropriate type which knows how to parse the data object) to provide a block of
11882  * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
11883  * <p>
11884  * Custom implementations must implement the load method as described in
11885  * {@link Roo.data.HttpProxy#load}.
11886  */
11887 Roo.data.DataProxy = function(){
11888     this.addEvents({
11889         /**
11890          * @event beforeload
11891          * Fires before a network request is made to retrieve a data object.
11892          * @param {Object} This DataProxy object.
11893          * @param {Object} params The params parameter to the load function.
11894          */
11895         beforeload : true,
11896         /**
11897          * @event load
11898          * Fires before the load method's callback is called.
11899          * @param {Object} This DataProxy object.
11900          * @param {Object} o The data object.
11901          * @param {Object} arg The callback argument object passed to the load function.
11902          */
11903         load : true,
11904         /**
11905          * @event loadexception
11906          * Fires if an Exception occurs during data retrieval.
11907          * @param {Object} This DataProxy object.
11908          * @param {Object} o The data object.
11909          * @param {Object} arg The callback argument object passed to the load function.
11910          * @param {Object} e The Exception.
11911          */
11912         loadexception : true
11913     });
11914     Roo.data.DataProxy.superclass.constructor.call(this);
11915 };
11916
11917 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
11918
11919     /**
11920      * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
11921      */
11922 /*
11923  * Based on:
11924  * Ext JS Library 1.1.1
11925  * Copyright(c) 2006-2007, Ext JS, LLC.
11926  *
11927  * Originally Released Under LGPL - original licence link has changed is not relivant.
11928  *
11929  * Fork - LGPL
11930  * <script type="text/javascript">
11931  */
11932 /**
11933  * @class Roo.data.MemoryProxy
11934  * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
11935  * to the Reader when its load method is called.
11936  * @constructor
11937  * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
11938  */
11939 Roo.data.MemoryProxy = function(data){
11940     if (data.data) {
11941         data = data.data;
11942     }
11943     Roo.data.MemoryProxy.superclass.constructor.call(this);
11944     this.data = data;
11945 };
11946
11947 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
11948     
11949     /**
11950      * Load data from the requested source (in this case an in-memory
11951      * data object passed to the constructor), read the data object into
11952      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
11953      * process that block using the passed callback.
11954      * @param {Object} params This parameter is not used by the MemoryProxy class.
11955      * @param {Roo.data.DataReader} reader The Reader object which converts the data
11956      * object into a block of Roo.data.Records.
11957      * @param {Function} callback The function into which to pass the block of Roo.data.records.
11958      * The function must be passed <ul>
11959      * <li>The Record block object</li>
11960      * <li>The "arg" argument from the load function</li>
11961      * <li>A boolean success indicator</li>
11962      * </ul>
11963      * @param {Object} scope The scope in which to call the callback
11964      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
11965      */
11966     load : function(params, reader, callback, scope, arg){
11967         params = params || {};
11968         var result;
11969         try {
11970             result = reader.readRecords(this.data);
11971         }catch(e){
11972             this.fireEvent("loadexception", this, arg, null, e);
11973             callback.call(scope, null, arg, false);
11974             return;
11975         }
11976         callback.call(scope, result, arg, true);
11977     },
11978     
11979     // private
11980     update : function(params, records){
11981         
11982     }
11983 });/*
11984  * Based on:
11985  * Ext JS Library 1.1.1
11986  * Copyright(c) 2006-2007, Ext JS, LLC.
11987  *
11988  * Originally Released Under LGPL - original licence link has changed is not relivant.
11989  *
11990  * Fork - LGPL
11991  * <script type="text/javascript">
11992  */
11993 /**
11994  * @class Roo.data.HttpProxy
11995  * @extends Roo.data.DataProxy
11996  * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
11997  * configured to reference a certain URL.<br><br>
11998  * <p>
11999  * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12000  * from which the running page was served.<br><br>
12001  * <p>
12002  * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12003  * <p>
12004  * Be aware that to enable the browser to parse an XML document, the server must set
12005  * the Content-Type header in the HTTP response to "text/xml".
12006  * @constructor
12007  * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12008  * an {@link Roo.data.Connection} object.  If a Connection config is passed, the singleton {@link Roo.Ajax} object
12009  * will be used to make the request.
12010  */
12011 Roo.data.HttpProxy = function(conn){
12012     Roo.data.HttpProxy.superclass.constructor.call(this);
12013     // is conn a conn config or a real conn?
12014     this.conn = conn;
12015     this.useAjax = !conn || !conn.events;
12016   
12017 };
12018
12019 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12020     // thse are take from connection...
12021     
12022     /**
12023      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12024      */
12025     /**
12026      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12027      * extra parameters to each request made by this object. (defaults to undefined)
12028      */
12029     /**
12030      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12031      *  to each request made by this object. (defaults to undefined)
12032      */
12033     /**
12034      * @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)
12035      */
12036     /**
12037      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12038      */
12039      /**
12040      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12041      * @type Boolean
12042      */
12043   
12044
12045     /**
12046      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12047      * @type Boolean
12048      */
12049     /**
12050      * Return the {@link Roo.data.Connection} object being used by this Proxy.
12051      * @return {Connection} The Connection object. This object may be used to subscribe to events on
12052      * a finer-grained basis than the DataProxy events.
12053      */
12054     getConnection : function(){
12055         return this.useAjax ? Roo.Ajax : this.conn;
12056     },
12057
12058     /**
12059      * Load data from the configured {@link Roo.data.Connection}, read the data object into
12060      * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12061      * process that block using the passed callback.
12062      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12063      * for the request to the remote server.
12064      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12065      * object into a block of Roo.data.Records.
12066      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12067      * The function must be passed <ul>
12068      * <li>The Record block object</li>
12069      * <li>The "arg" argument from the load function</li>
12070      * <li>A boolean success indicator</li>
12071      * </ul>
12072      * @param {Object} scope The scope in which to call the callback
12073      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12074      */
12075     load : function(params, reader, callback, scope, arg){
12076         if(this.fireEvent("beforeload", this, params) !== false){
12077             var  o = {
12078                 params : params || {},
12079                 request: {
12080                     callback : callback,
12081                     scope : scope,
12082                     arg : arg
12083                 },
12084                 reader: reader,
12085                 callback : this.loadResponse,
12086                 scope: this
12087             };
12088             if(this.useAjax){
12089                 Roo.applyIf(o, this.conn);
12090                 if(this.activeRequest){
12091                     Roo.Ajax.abort(this.activeRequest);
12092                 }
12093                 this.activeRequest = Roo.Ajax.request(o);
12094             }else{
12095                 this.conn.request(o);
12096             }
12097         }else{
12098             callback.call(scope||this, null, arg, false);
12099         }
12100     },
12101
12102     // private
12103     loadResponse : function(o, success, response){
12104         delete this.activeRequest;
12105         if(!success){
12106             this.fireEvent("loadexception", this, o, response);
12107             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12108             return;
12109         }
12110         var result;
12111         try {
12112             result = o.reader.read(response);
12113         }catch(e){
12114             this.fireEvent("loadexception", this, o, response, e);
12115             o.request.callback.call(o.request.scope, null, o.request.arg, false);
12116             return;
12117         }
12118         
12119         this.fireEvent("load", this, o, o.request.arg);
12120         o.request.callback.call(o.request.scope, result, o.request.arg, true);
12121     },
12122
12123     // private
12124     update : function(dataSet){
12125
12126     },
12127
12128     // private
12129     updateResponse : function(dataSet){
12130
12131     }
12132 });/*
12133  * Based on:
12134  * Ext JS Library 1.1.1
12135  * Copyright(c) 2006-2007, Ext JS, LLC.
12136  *
12137  * Originally Released Under LGPL - original licence link has changed is not relivant.
12138  *
12139  * Fork - LGPL
12140  * <script type="text/javascript">
12141  */
12142
12143 /**
12144  * @class Roo.data.ScriptTagProxy
12145  * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12146  * other than the originating domain of the running page.<br><br>
12147  * <p>
12148  * <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
12149  * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12150  * <p>
12151  * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12152  * source code that is used as the source inside a &lt;script> tag.<br><br>
12153  * <p>
12154  * In order for the browser to process the returned data, the server must wrap the data object
12155  * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12156  * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12157  * depending on whether the callback name was passed:
12158  * <p>
12159  * <pre><code>
12160 boolean scriptTag = false;
12161 String cb = request.getParameter("callback");
12162 if (cb != null) {
12163     scriptTag = true;
12164     response.setContentType("text/javascript");
12165 } else {
12166     response.setContentType("application/x-json");
12167 }
12168 Writer out = response.getWriter();
12169 if (scriptTag) {
12170     out.write(cb + "(");
12171 }
12172 out.print(dataBlock.toJsonString());
12173 if (scriptTag) {
12174     out.write(");");
12175 }
12176 </pre></code>
12177  *
12178  * @constructor
12179  * @param {Object} config A configuration object.
12180  */
12181 Roo.data.ScriptTagProxy = function(config){
12182     Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12183     Roo.apply(this, config);
12184     this.head = document.getElementsByTagName("head")[0];
12185 };
12186
12187 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12188
12189 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12190     /**
12191      * @cfg {String} url The URL from which to request the data object.
12192      */
12193     /**
12194      * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12195      */
12196     timeout : 30000,
12197     /**
12198      * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12199      * the server the name of the callback function set up by the load call to process the returned data object.
12200      * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12201      * javascript output which calls this named function passing the data object as its only parameter.
12202      */
12203     callbackParam : "callback",
12204     /**
12205      *  @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12206      * name to the request.
12207      */
12208     nocache : true,
12209
12210     /**
12211      * Load data from the configured URL, read the data object into
12212      * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12213      * process that block using the passed callback.
12214      * @param {Object} params An object containing properties which are to be used as HTTP parameters
12215      * for the request to the remote server.
12216      * @param {Roo.data.DataReader} reader The Reader object which converts the data
12217      * object into a block of Roo.data.Records.
12218      * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12219      * The function must be passed <ul>
12220      * <li>The Record block object</li>
12221      * <li>The "arg" argument from the load function</li>
12222      * <li>A boolean success indicator</li>
12223      * </ul>
12224      * @param {Object} scope The scope in which to call the callback
12225      * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12226      */
12227     load : function(params, reader, callback, scope, arg){
12228         if(this.fireEvent("beforeload", this, params) !== false){
12229
12230             var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12231
12232             var url = this.url;
12233             url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12234             if(this.nocache){
12235                 url += "&_dc=" + (new Date().getTime());
12236             }
12237             var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12238             var trans = {
12239                 id : transId,
12240                 cb : "stcCallback"+transId,
12241                 scriptId : "stcScript"+transId,
12242                 params : params,
12243                 arg : arg,
12244                 url : url,
12245                 callback : callback,
12246                 scope : scope,
12247                 reader : reader
12248             };
12249             var conn = this;
12250
12251             window[trans.cb] = function(o){
12252                 conn.handleResponse(o, trans);
12253             };
12254
12255             url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12256
12257             if(this.autoAbort !== false){
12258                 this.abort();
12259             }
12260
12261             trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12262
12263             var script = document.createElement("script");
12264             script.setAttribute("src", url);
12265             script.setAttribute("type", "text/javascript");
12266             script.setAttribute("id", trans.scriptId);
12267             this.head.appendChild(script);
12268
12269             this.trans = trans;
12270         }else{
12271             callback.call(scope||this, null, arg, false);
12272         }
12273     },
12274
12275     // private
12276     isLoading : function(){
12277         return this.trans ? true : false;
12278     },
12279
12280     /**
12281      * Abort the current server request.
12282      */
12283     abort : function(){
12284         if(this.isLoading()){
12285             this.destroyTrans(this.trans);
12286         }
12287     },
12288
12289     // private
12290     destroyTrans : function(trans, isLoaded){
12291         this.head.removeChild(document.getElementById(trans.scriptId));
12292         clearTimeout(trans.timeoutId);
12293         if(isLoaded){
12294             window[trans.cb] = undefined;
12295             try{
12296                 delete window[trans.cb];
12297             }catch(e){}
12298         }else{
12299             // if hasn't been loaded, wait for load to remove it to prevent script error
12300             window[trans.cb] = function(){
12301                 window[trans.cb] = undefined;
12302                 try{
12303                     delete window[trans.cb];
12304                 }catch(e){}
12305             };
12306         }
12307     },
12308
12309     // private
12310     handleResponse : function(o, trans){
12311         this.trans = false;
12312         this.destroyTrans(trans, true);
12313         var result;
12314         try {
12315             result = trans.reader.readRecords(o);
12316         }catch(e){
12317             this.fireEvent("loadexception", this, o, trans.arg, e);
12318             trans.callback.call(trans.scope||window, null, trans.arg, false);
12319             return;
12320         }
12321         this.fireEvent("load", this, o, trans.arg);
12322         trans.callback.call(trans.scope||window, result, trans.arg, true);
12323     },
12324
12325     // private
12326     handleFailure : function(trans){
12327         this.trans = false;
12328         this.destroyTrans(trans, false);
12329         this.fireEvent("loadexception", this, null, trans.arg);
12330         trans.callback.call(trans.scope||window, null, trans.arg, false);
12331     }
12332 });/*
12333  * Based on:
12334  * Ext JS Library 1.1.1
12335  * Copyright(c) 2006-2007, Ext JS, LLC.
12336  *
12337  * Originally Released Under LGPL - original licence link has changed is not relivant.
12338  *
12339  * Fork - LGPL
12340  * <script type="text/javascript">
12341  */
12342
12343 /**
12344  * @class Roo.data.JsonReader
12345  * @extends Roo.data.DataReader
12346  * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12347  * based on mappings in a provided Roo.data.Record constructor.
12348  * 
12349  * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12350  * in the reply previously. 
12351  * 
12352  * <p>
12353  * Example code:
12354  * <pre><code>
12355 var RecordDef = Roo.data.Record.create([
12356     {name: 'name', mapping: 'name'},     // "mapping" property not needed if it's the same as "name"
12357     {name: 'occupation'}                 // This field will use "occupation" as the mapping.
12358 ]);
12359 var myReader = new Roo.data.JsonReader({
12360     totalProperty: "results",    // The property which contains the total dataset size (optional)
12361     root: "rows",                // The property which contains an Array of row objects
12362     id: "id"                     // The property within each row object that provides an ID for the record (optional)
12363 }, RecordDef);
12364 </code></pre>
12365  * <p>
12366  * This would consume a JSON file like this:
12367  * <pre><code>
12368 { 'results': 2, 'rows': [
12369     { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12370     { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12371 }
12372 </code></pre>
12373  * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12374  * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12375  * paged from the remote server.
12376  * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12377  * @cfg {String} root name of the property which contains the Array of row objects.
12378  * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12379  * @cfg {Array} fields Array of field definition objects
12380  * @constructor
12381  * Create a new JsonReader
12382  * @param {Object} meta Metadata configuration options
12383  * @param {Object} recordType Either an Array of field definition objects,
12384  * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12385  */
12386 Roo.data.JsonReader = function(meta, recordType){
12387     
12388     meta = meta || {};
12389     // set some defaults:
12390     Roo.applyIf(meta, {
12391         totalProperty: 'total',
12392         successProperty : 'success',
12393         root : 'data',
12394         id : 'id'
12395     });
12396     
12397     Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12398 };
12399 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12400     
12401     /**
12402      * @prop {Boolean} metaFromRemote  - if the meta data was loaded from the remote source.
12403      * Used by Store query builder to append _requestMeta to params.
12404      * 
12405      */
12406     metaFromRemote : false,
12407     /**
12408      * This method is only used by a DataProxy which has retrieved data from a remote server.
12409      * @param {Object} response The XHR object which contains the JSON data in its responseText.
12410      * @return {Object} data A data block which is used by an Roo.data.Store object as
12411      * a cache of Roo.data.Records.
12412      */
12413     read : function(response){
12414         var json = response.responseText;
12415        
12416         var o = /* eval:var:o */ eval("("+json+")");
12417         if(!o) {
12418             throw {message: "JsonReader.read: Json object not found"};
12419         }
12420         
12421         if(o.metaData){
12422             
12423             delete this.ef;
12424             this.metaFromRemote = true;
12425             this.meta = o.metaData;
12426             this.recordType = Roo.data.Record.create(o.metaData.fields);
12427             this.onMetaChange(this.meta, this.recordType, o);
12428         }
12429         return this.readRecords(o);
12430     },
12431
12432     // private function a store will implement
12433     onMetaChange : function(meta, recordType, o){
12434
12435     },
12436
12437     /**
12438          * @ignore
12439          */
12440     simpleAccess: function(obj, subsc) {
12441         return obj[subsc];
12442     },
12443
12444         /**
12445          * @ignore
12446          */
12447     getJsonAccessor: function(){
12448         var re = /[\[\.]/;
12449         return function(expr) {
12450             try {
12451                 return(re.test(expr))
12452                     ? new Function("obj", "return obj." + expr)
12453                     : function(obj){
12454                         return obj[expr];
12455                     };
12456             } catch(e){}
12457             return Roo.emptyFn;
12458         };
12459     }(),
12460
12461     /**
12462      * Create a data block containing Roo.data.Records from an XML document.
12463      * @param {Object} o An object which contains an Array of row objects in the property specified
12464      * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12465      * which contains the total size of the dataset.
12466      * @return {Object} data A data block which is used by an Roo.data.Store object as
12467      * a cache of Roo.data.Records.
12468      */
12469     readRecords : function(o){
12470         /**
12471          * After any data loads, the raw JSON data is available for further custom processing.
12472          * @type Object
12473          */
12474         this.o = o;
12475         var s = this.meta, Record = this.recordType,
12476             f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12477
12478 //      Generate extraction functions for the totalProperty, the root, the id, and for each field
12479         if (!this.ef) {
12480             if(s.totalProperty) {
12481                     this.getTotal = this.getJsonAccessor(s.totalProperty);
12482                 }
12483                 if(s.successProperty) {
12484                     this.getSuccess = this.getJsonAccessor(s.successProperty);
12485                 }
12486                 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12487                 if (s.id) {
12488                         var g = this.getJsonAccessor(s.id);
12489                         this.getId = function(rec) {
12490                                 var r = g(rec);  
12491                                 return (r === undefined || r === "") ? null : r;
12492                         };
12493                 } else {
12494                         this.getId = function(){return null;};
12495                 }
12496             this.ef = [];
12497             for(var jj = 0; jj < fl; jj++){
12498                 f = fi[jj];
12499                 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12500                 this.ef[jj] = this.getJsonAccessor(map);
12501             }
12502         }
12503
12504         var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12505         if(s.totalProperty){
12506             var vt = parseInt(this.getTotal(o), 10);
12507             if(!isNaN(vt)){
12508                 totalRecords = vt;
12509             }
12510         }
12511         if(s.successProperty){
12512             var vs = this.getSuccess(o);
12513             if(vs === false || vs === 'false'){
12514                 success = false;
12515             }
12516         }
12517         var records = [];
12518         for(var i = 0; i < c; i++){
12519                 var n = root[i];
12520             var values = {};
12521             var id = this.getId(n);
12522             for(var j = 0; j < fl; j++){
12523                 f = fi[j];
12524             var v = this.ef[j](n);
12525             if (!f.convert) {
12526                 Roo.log('missing convert for ' + f.name);
12527                 Roo.log(f);
12528                 continue;
12529             }
12530             values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12531             }
12532             var record = new Record(values, id);
12533             record.json = n;
12534             records[i] = record;
12535         }
12536         return {
12537             raw : o,
12538             success : success,
12539             records : records,
12540             totalRecords : totalRecords
12541         };
12542     }
12543 });/*
12544  * Based on:
12545  * Ext JS Library 1.1.1
12546  * Copyright(c) 2006-2007, Ext JS, LLC.
12547  *
12548  * Originally Released Under LGPL - original licence link has changed is not relivant.
12549  *
12550  * Fork - LGPL
12551  * <script type="text/javascript">
12552  */
12553
12554 /**
12555  * @class Roo.data.ArrayReader
12556  * @extends Roo.data.DataReader
12557  * Data reader class to create an Array of Roo.data.Record objects from an Array.
12558  * Each element of that Array represents a row of data fields. The
12559  * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12560  * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12561  * <p>
12562  * Example code:.
12563  * <pre><code>
12564 var RecordDef = Roo.data.Record.create([
12565     {name: 'name', mapping: 1},         // "mapping" only needed if an "id" field is present which
12566     {name: 'occupation', mapping: 2}    // precludes using the ordinal position as the index.
12567 ]);
12568 var myReader = new Roo.data.ArrayReader({
12569     id: 0                     // The subscript within row Array that provides an ID for the Record (optional)
12570 }, RecordDef);
12571 </code></pre>
12572  * <p>
12573  * This would consume an Array like this:
12574  * <pre><code>
12575 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12576   </code></pre>
12577  * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12578  * @constructor
12579  * Create a new JsonReader
12580  * @param {Object} meta Metadata configuration options.
12581  * @param {Object} recordType Either an Array of field definition objects
12582  * as specified to {@link Roo.data.Record#create},
12583  * or an {@link Roo.data.Record} object
12584  * created using {@link Roo.data.Record#create}.
12585  */
12586 Roo.data.ArrayReader = function(meta, recordType){
12587     Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12588 };
12589
12590 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12591     /**
12592      * Create a data block containing Roo.data.Records from an XML document.
12593      * @param {Object} o An Array of row objects which represents the dataset.
12594      * @return {Object} data A data block which is used by an Roo.data.Store object as
12595      * a cache of Roo.data.Records.
12596      */
12597     readRecords : function(o){
12598         var sid = this.meta ? this.meta.id : null;
12599         var recordType = this.recordType, fields = recordType.prototype.fields;
12600         var records = [];
12601         var root = o;
12602             for(var i = 0; i < root.length; i++){
12603                     var n = root[i];
12604                 var values = {};
12605                 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12606                 for(var j = 0, jlen = fields.length; j < jlen; j++){
12607                 var f = fields.items[j];
12608                 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12609                 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12610                 v = f.convert(v);
12611                 values[f.name] = v;
12612             }
12613                 var record = new recordType(values, id);
12614                 record.json = n;
12615                 records[records.length] = record;
12616             }
12617             return {
12618                 records : records,
12619                 totalRecords : records.length
12620             };
12621     }
12622 });/*
12623  * - LGPL
12624  * * 
12625  */
12626
12627 /**
12628  * @class Roo.bootstrap.ComboBox
12629  * @extends Roo.bootstrap.TriggerField
12630  * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12631  * @cfg {Boolean} append (true|false) default false
12632  * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12633  * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12634  * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12635  * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12636  * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12637  * @cfg {Boolean} animate default true
12638  * @cfg {Boolean} emptyResultText only for touch device
12639  * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12640  * @cfg {String} emptyTitle default ''
12641  * @constructor
12642  * Create a new ComboBox.
12643  * @param {Object} config Configuration options
12644  */
12645 Roo.bootstrap.ComboBox = function(config){
12646     Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12647     this.addEvents({
12648         /**
12649          * @event expand
12650          * Fires when the dropdown list is expanded
12651         * @param {Roo.bootstrap.ComboBox} combo This combo box
12652         */
12653         'expand' : true,
12654         /**
12655          * @event collapse
12656          * Fires when the dropdown list is collapsed
12657         * @param {Roo.bootstrap.ComboBox} combo This combo box
12658         */
12659         'collapse' : true,
12660         /**
12661          * @event beforeselect
12662          * Fires before a list item is selected. Return false to cancel the selection.
12663         * @param {Roo.bootstrap.ComboBox} combo This combo box
12664         * @param {Roo.data.Record} record The data record returned from the underlying store
12665         * @param {Number} index The index of the selected item in the dropdown list
12666         */
12667         'beforeselect' : true,
12668         /**
12669          * @event select
12670          * Fires when a list item is selected
12671         * @param {Roo.bootstrap.ComboBox} combo This combo box
12672         * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12673         * @param {Number} index The index of the selected item in the dropdown list
12674         */
12675         'select' : true,
12676         /**
12677          * @event beforequery
12678          * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12679          * The event object passed has these properties:
12680         * @param {Roo.bootstrap.ComboBox} combo This combo box
12681         * @param {String} query The query
12682         * @param {Boolean} forceAll true to force "all" query
12683         * @param {Boolean} cancel true to cancel the query
12684         * @param {Object} e The query event object
12685         */
12686         'beforequery': true,
12687          /**
12688          * @event add
12689          * Fires when the 'add' icon is pressed (add a listener to enable add button)
12690         * @param {Roo.bootstrap.ComboBox} combo This combo box
12691         */
12692         'add' : true,
12693         /**
12694          * @event edit
12695          * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12696         * @param {Roo.bootstrap.ComboBox} combo This combo box
12697         * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12698         */
12699         'edit' : true,
12700         /**
12701          * @event remove
12702          * Fires when the remove value from the combobox array
12703         * @param {Roo.bootstrap.ComboBox} combo This combo box
12704         */
12705         'remove' : true,
12706         /**
12707          * @event afterremove
12708          * Fires when the remove value from the combobox array
12709         * @param {Roo.bootstrap.ComboBox} combo This combo box
12710         */
12711         'afterremove' : true,
12712         /**
12713          * @event specialfilter
12714          * Fires when specialfilter
12715             * @param {Roo.bootstrap.ComboBox} combo This combo box
12716             */
12717         'specialfilter' : true,
12718         /**
12719          * @event tick
12720          * Fires when tick the element
12721             * @param {Roo.bootstrap.ComboBox} combo This combo box
12722             */
12723         'tick' : true,
12724         /**
12725          * @event touchviewdisplay
12726          * Fires when touch view require special display (default is using displayField)
12727             * @param {Roo.bootstrap.ComboBox} combo This combo box
12728             * @param {Object} cfg set html .
12729             */
12730         'touchviewdisplay' : true
12731         
12732     });
12733     
12734     this.item = [];
12735     this.tickItems = [];
12736     
12737     this.selectedIndex = -1;
12738     if(this.mode == 'local'){
12739         if(config.queryDelay === undefined){
12740             this.queryDelay = 10;
12741         }
12742         if(config.minChars === undefined){
12743             this.minChars = 0;
12744         }
12745     }
12746 };
12747
12748 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
12749      
12750     /**
12751      * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
12752      * rendering into an Roo.Editor, defaults to false)
12753      */
12754     /**
12755      * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
12756      * {tag: "input", type: "text", size: "24", autocomplete: "off"})
12757      */
12758     /**
12759      * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
12760      */
12761     /**
12762      * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
12763      * the dropdown list (defaults to undefined, with no header element)
12764      */
12765
12766      /**
12767      * @cfg {String/Roo.Template} tpl The template to use to render the output
12768      */
12769      
12770      /**
12771      * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
12772      */
12773     listWidth: undefined,
12774     /**
12775      * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
12776      * mode = 'remote' or 'text' if mode = 'local')
12777      */
12778     displayField: undefined,
12779     
12780     /**
12781      * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
12782      * mode = 'remote' or 'value' if mode = 'local'). 
12783      * Note: use of a valueField requires the user make a selection
12784      * in order for a value to be mapped.
12785      */
12786     valueField: undefined,
12787     /**
12788      * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
12789      */
12790     modalTitle : '',
12791     
12792     /**
12793      * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
12794      * field's data value (defaults to the underlying DOM element's name)
12795      */
12796     hiddenName: undefined,
12797     /**
12798      * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
12799      */
12800     listClass: '',
12801     /**
12802      * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
12803      */
12804     selectedClass: 'active',
12805     
12806     /**
12807      * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
12808      */
12809     shadow:'sides',
12810     /**
12811      * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
12812      * anchor positions (defaults to 'tl-bl')
12813      */
12814     listAlign: 'tl-bl?',
12815     /**
12816      * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
12817      */
12818     maxHeight: 300,
12819     /**
12820      * @cfg {String} triggerAction The action to execute when the trigger field is activated.  Use 'all' to run the
12821      * query specified by the allQuery config option (defaults to 'query')
12822      */
12823     triggerAction: 'query',
12824     /**
12825      * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
12826      * (defaults to 4, does not apply if editable = false)
12827      */
12828     minChars : 4,
12829     /**
12830      * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
12831      * delay (typeAheadDelay) if it matches a known value (defaults to false)
12832      */
12833     typeAhead: false,
12834     /**
12835      * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
12836      * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
12837      */
12838     queryDelay: 500,
12839     /**
12840      * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
12841      * filter queries will execute with page start and limit parameters.  Only applies when mode = 'remote' (defaults to 0)
12842      */
12843     pageSize: 0,
12844     /**
12845      * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus.  Only applies
12846      * when editable = true (defaults to false)
12847      */
12848     selectOnFocus:false,
12849     /**
12850      * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
12851      */
12852     queryParam: 'query',
12853     /**
12854      * @cfg {String} loadingText The text to display in the dropdown list while data is loading.  Only applies
12855      * when mode = 'remote' (defaults to 'Loading...')
12856      */
12857     loadingText: 'Loading...',
12858     /**
12859      * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
12860      */
12861     resizable: false,
12862     /**
12863      * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
12864      */
12865     handleHeight : 8,
12866     /**
12867      * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
12868      * traditional select (defaults to true)
12869      */
12870     editable: true,
12871     /**
12872      * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
12873      */
12874     allQuery: '',
12875     /**
12876      * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
12877      */
12878     mode: 'remote',
12879     /**
12880      * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
12881      * listWidth has a higher value)
12882      */
12883     minListWidth : 70,
12884     /**
12885      * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
12886      * allow the user to set arbitrary text into the field (defaults to false)
12887      */
12888     forceSelection:false,
12889     /**
12890      * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
12891      * if typeAhead = true (defaults to 250)
12892      */
12893     typeAheadDelay : 250,
12894     /**
12895      * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
12896      * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
12897      */
12898     valueNotFoundText : undefined,
12899     /**
12900      * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
12901      */
12902     blockFocus : false,
12903     
12904     /**
12905      * @cfg {Boolean} disableClear Disable showing of clear button.
12906      */
12907     disableClear : false,
12908     /**
12909      * @cfg {Boolean} alwaysQuery  Disable caching of results, and always send query
12910      */
12911     alwaysQuery : false,
12912     
12913     /**
12914      * @cfg {Boolean} multiple  (true|false) ComboBobArray, default false
12915      */
12916     multiple : false,
12917     
12918     /**
12919      * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
12920      */
12921     invalidClass : "has-warning",
12922     
12923     /**
12924      * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
12925      */
12926     validClass : "has-success",
12927     
12928     /**
12929      * @cfg {Boolean} specialFilter (true|false) special filter default false
12930      */
12931     specialFilter : false,
12932     
12933     /**
12934      * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
12935      */
12936     mobileTouchView : true,
12937     
12938     /**
12939      * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
12940      */
12941     useNativeIOS : false,
12942     
12943     ios_options : false,
12944     
12945     //private
12946     addicon : false,
12947     editicon: false,
12948     
12949     page: 0,
12950     hasQuery: false,
12951     append: false,
12952     loadNext: false,
12953     autoFocus : true,
12954     tickable : false,
12955     btnPosition : 'right',
12956     triggerList : true,
12957     showToggleBtn : true,
12958     animate : true,
12959     emptyResultText: 'Empty',
12960     triggerText : 'Select',
12961     emptyTitle : '',
12962     
12963     // element that contains real text value.. (when hidden is used..)
12964     
12965     getAutoCreate : function()
12966     {   
12967         var cfg = false;
12968         //render
12969         /*
12970          * Render classic select for iso
12971          */
12972         
12973         if(Roo.isIOS && this.useNativeIOS){
12974             cfg = this.getAutoCreateNativeIOS();
12975             return cfg;
12976         }
12977         
12978         /*
12979          * Touch Devices
12980          */
12981         
12982         if(Roo.isTouch && this.mobileTouchView){
12983             cfg = this.getAutoCreateTouchView();
12984             return cfg;;
12985         }
12986         
12987         /*
12988          *  Normal ComboBox
12989          */
12990         if(!this.tickable){
12991             cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
12992             return cfg;
12993         }
12994         
12995         /*
12996          *  ComboBox with tickable selections
12997          */
12998              
12999         var align = this.labelAlign || this.parentLabelAlign();
13000         
13001         cfg = {
13002             cls : 'form-group roo-combobox-tickable' //input-group
13003         };
13004         
13005         var btn_text_select = '';
13006         var btn_text_done = '';
13007         var btn_text_cancel = '';
13008         
13009         if (this.btn_text_show) {
13010             btn_text_select = 'Select';
13011             btn_text_done = 'Done';
13012             btn_text_cancel = 'Cancel'; 
13013         }
13014         
13015         var buttons = {
13016             tag : 'div',
13017             cls : 'tickable-buttons',
13018             cn : [
13019                 {
13020                     tag : 'button',
13021                     type : 'button',
13022                     cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13023                     //html : this.triggerText
13024                     html: btn_text_select
13025                 },
13026                 {
13027                     tag : 'button',
13028                     type : 'button',
13029                     name : 'ok',
13030                     cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13031                     //html : 'Done'
13032                     html: btn_text_done
13033                 },
13034                 {
13035                     tag : 'button',
13036                     type : 'button',
13037                     name : 'cancel',
13038                     cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13039                     //html : 'Cancel'
13040                     html: btn_text_cancel
13041                 }
13042             ]
13043         };
13044         
13045         if(this.editable){
13046             buttons.cn.unshift({
13047                 tag: 'input',
13048                 cls: 'roo-select2-search-field-input'
13049             });
13050         }
13051         
13052         var _this = this;
13053         
13054         Roo.each(buttons.cn, function(c){
13055             if (_this.size) {
13056                 c.cls += ' btn-' + _this.size;
13057             }
13058
13059             if (_this.disabled) {
13060                 c.disabled = true;
13061             }
13062         });
13063         
13064         var box = {
13065             tag: 'div',
13066             cn: [
13067                 {
13068                     tag: 'input',
13069                     type : 'hidden',
13070                     cls: 'form-hidden-field'
13071                 },
13072                 {
13073                     tag: 'ul',
13074                     cls: 'roo-select2-choices',
13075                     cn:[
13076                         {
13077                             tag: 'li',
13078                             cls: 'roo-select2-search-field',
13079                             cn: [
13080                                 buttons
13081                             ]
13082                         }
13083                     ]
13084                 }
13085             ]
13086         };
13087         
13088         var combobox = {
13089             cls: 'roo-select2-container input-group roo-select2-container-multi',
13090             cn: [
13091                 box
13092 //                {
13093 //                    tag: 'ul',
13094 //                    cls: 'typeahead typeahead-long dropdown-menu',
13095 //                    style: 'display:none; max-height:' + this.maxHeight + 'px;'
13096 //                }
13097             ]
13098         };
13099         
13100         if(this.hasFeedback && !this.allowBlank){
13101             
13102             var feedback = {
13103                 tag: 'span',
13104                 cls: 'glyphicon form-control-feedback'
13105             };
13106
13107             combobox.cn.push(feedback);
13108         }
13109         
13110         
13111         if (align ==='left' && this.fieldLabel.length) {
13112             
13113             cfg.cls += ' roo-form-group-label-left';
13114             
13115             cfg.cn = [
13116                 {
13117                     tag : 'i',
13118                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13119                     tooltip : 'This field is required'
13120                 },
13121                 {
13122                     tag: 'label',
13123                     'for' :  id,
13124                     cls : 'control-label',
13125                     html : this.fieldLabel
13126
13127                 },
13128                 {
13129                     cls : "", 
13130                     cn: [
13131                         combobox
13132                     ]
13133                 }
13134
13135             ];
13136             
13137             var labelCfg = cfg.cn[1];
13138             var contentCfg = cfg.cn[2];
13139             
13140
13141             if(this.indicatorpos == 'right'){
13142                 
13143                 cfg.cn = [
13144                     {
13145                         tag: 'label',
13146                         'for' :  id,
13147                         cls : 'control-label',
13148                         cn : [
13149                             {
13150                                 tag : 'span',
13151                                 html : this.fieldLabel
13152                             },
13153                             {
13154                                 tag : 'i',
13155                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13156                                 tooltip : 'This field is required'
13157                             }
13158                         ]
13159                     },
13160                     {
13161                         cls : "",
13162                         cn: [
13163                             combobox
13164                         ]
13165                     }
13166
13167                 ];
13168                 
13169                 
13170                 
13171                 labelCfg = cfg.cn[0];
13172                 contentCfg = cfg.cn[1];
13173             
13174             }
13175             
13176             if(this.labelWidth > 12){
13177                 labelCfg.style = "width: " + this.labelWidth + 'px';
13178             }
13179             
13180             if(this.labelWidth < 13 && this.labelmd == 0){
13181                 this.labelmd = this.labelWidth;
13182             }
13183             
13184             if(this.labellg > 0){
13185                 labelCfg.cls += ' col-lg-' + this.labellg;
13186                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13187             }
13188             
13189             if(this.labelmd > 0){
13190                 labelCfg.cls += ' col-md-' + this.labelmd;
13191                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13192             }
13193             
13194             if(this.labelsm > 0){
13195                 labelCfg.cls += ' col-sm-' + this.labelsm;
13196                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13197             }
13198             
13199             if(this.labelxs > 0){
13200                 labelCfg.cls += ' col-xs-' + this.labelxs;
13201                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13202             }
13203                 
13204                 
13205         } else if ( this.fieldLabel.length) {
13206 //                Roo.log(" label");
13207                  cfg.cn = [
13208                     {
13209                         tag : 'i',
13210                         cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
13211                         tooltip : 'This field is required'
13212                     },
13213                     {
13214                         tag: 'label',
13215                         //cls : 'input-group-addon',
13216                         html : this.fieldLabel
13217                     },
13218                     combobox
13219                 ];
13220                 
13221                 if(this.indicatorpos == 'right'){
13222                     cfg.cn = [
13223                         {
13224                             tag: 'label',
13225                             //cls : 'input-group-addon',
13226                             html : this.fieldLabel
13227                         },
13228                         {
13229                             tag : 'i',
13230                             cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
13231                             tooltip : 'This field is required'
13232                         },
13233                         combobox
13234                     ];
13235                     
13236                 }
13237
13238         } else {
13239             
13240 //                Roo.log(" no label && no align");
13241                 cfg = combobox
13242                      
13243                 
13244         }
13245          
13246         var settings=this;
13247         ['xs','sm','md','lg'].map(function(size){
13248             if (settings[size]) {
13249                 cfg.cls += ' col-' + size + '-' + settings[size];
13250             }
13251         });
13252         
13253         return cfg;
13254         
13255     },
13256     
13257     _initEventsCalled : false,
13258     
13259     // private
13260     initEvents: function()
13261     {   
13262         if (this._initEventsCalled) { // as we call render... prevent looping...
13263             return;
13264         }
13265         this._initEventsCalled = true;
13266         
13267         if (!this.store) {
13268             throw "can not find store for combo";
13269         }
13270         
13271         this.indicator = this.indicatorEl();
13272         
13273         this.store = Roo.factory(this.store, Roo.data);
13274         this.store.parent = this;
13275         
13276         // if we are building from html. then this element is so complex, that we can not really
13277         // use the rendered HTML.
13278         // so we have to trash and replace the previous code.
13279         if (Roo.XComponent.build_from_html) {
13280             // remove this element....
13281             var e = this.el.dom, k=0;
13282             while (e ) { e = e.previousSibling;  ++k;}
13283
13284             this.el.remove();
13285             
13286             this.el=false;
13287             this.rendered = false;
13288             
13289             this.render(this.parent().getChildContainer(true), k);
13290         }
13291         
13292         if(Roo.isIOS && this.useNativeIOS){
13293             this.initIOSView();
13294             return;
13295         }
13296         
13297         /*
13298          * Touch Devices
13299          */
13300         
13301         if(Roo.isTouch && this.mobileTouchView){
13302             this.initTouchView();
13303             return;
13304         }
13305         
13306         if(this.tickable){
13307             this.initTickableEvents();
13308             return;
13309         }
13310         
13311         Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13312         
13313         if(this.hiddenName){
13314             
13315             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13316             
13317             this.hiddenField.dom.value =
13318                 this.hiddenValue !== undefined ? this.hiddenValue :
13319                 this.value !== undefined ? this.value : '';
13320
13321             // prevent input submission
13322             this.el.dom.removeAttribute('name');
13323             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13324              
13325              
13326         }
13327         //if(Roo.isGecko){
13328         //    this.el.dom.setAttribute('autocomplete', 'off');
13329         //}
13330         
13331         var cls = 'x-combo-list';
13332         
13333         //this.list = new Roo.Layer({
13334         //    shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13335         //});
13336         
13337         var _this = this;
13338         
13339         (function(){
13340             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13341             _this.list.setWidth(lw);
13342         }).defer(100);
13343         
13344         this.list.on('mouseover', this.onViewOver, this);
13345         this.list.on('mousemove', this.onViewMove, this);
13346         this.list.on('scroll', this.onViewScroll, this);
13347         
13348         /*
13349         this.list.swallowEvent('mousewheel');
13350         this.assetHeight = 0;
13351
13352         if(this.title){
13353             this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13354             this.assetHeight += this.header.getHeight();
13355         }
13356
13357         this.innerList = this.list.createChild({cls:cls+'-inner'});
13358         this.innerList.on('mouseover', this.onViewOver, this);
13359         this.innerList.on('mousemove', this.onViewMove, this);
13360         this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13361         
13362         if(this.allowBlank && !this.pageSize && !this.disableClear){
13363             this.footer = this.list.createChild({cls:cls+'-ft'});
13364             this.pageTb = new Roo.Toolbar(this.footer);
13365            
13366         }
13367         if(this.pageSize){
13368             this.footer = this.list.createChild({cls:cls+'-ft'});
13369             this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13370                     {pageSize: this.pageSize});
13371             
13372         }
13373         
13374         if (this.pageTb && this.allowBlank && !this.disableClear) {
13375             var _this = this;
13376             this.pageTb.add(new Roo.Toolbar.Fill(), {
13377                 cls: 'x-btn-icon x-btn-clear',
13378                 text: '&#160;',
13379                 handler: function()
13380                 {
13381                     _this.collapse();
13382                     _this.clearValue();
13383                     _this.onSelect(false, -1);
13384                 }
13385             });
13386         }
13387         if (this.footer) {
13388             this.assetHeight += this.footer.getHeight();
13389         }
13390         */
13391             
13392         if(!this.tpl){
13393             this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
13394         }
13395
13396         this.view = new Roo.View(this.list, this.tpl, {
13397             singleSelect:true, store: this.store, selectedClass: this.selectedClass
13398         });
13399         //this.view.wrapEl.setDisplayed(false);
13400         this.view.on('click', this.onViewClick, this);
13401         
13402         
13403         this.store.on('beforeload', this.onBeforeLoad, this);
13404         this.store.on('load', this.onLoad, this);
13405         this.store.on('loadexception', this.onLoadException, this);
13406         /*
13407         if(this.resizable){
13408             this.resizer = new Roo.Resizable(this.list,  {
13409                pinned:true, handles:'se'
13410             });
13411             this.resizer.on('resize', function(r, w, h){
13412                 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13413                 this.listWidth = w;
13414                 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13415                 this.restrictHeight();
13416             }, this);
13417             this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13418         }
13419         */
13420         if(!this.editable){
13421             this.editable = true;
13422             this.setEditable(false);
13423         }
13424         
13425         /*
13426         
13427         if (typeof(this.events.add.listeners) != 'undefined') {
13428             
13429             this.addicon = this.wrap.createChild(
13430                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });  
13431        
13432             this.addicon.on('click', function(e) {
13433                 this.fireEvent('add', this);
13434             }, this);
13435         }
13436         if (typeof(this.events.edit.listeners) != 'undefined') {
13437             
13438             this.editicon = this.wrap.createChild(
13439                 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });  
13440             if (this.addicon) {
13441                 this.editicon.setStyle('margin-left', '40px');
13442             }
13443             this.editicon.on('click', function(e) {
13444                 
13445                 // we fire even  if inothing is selected..
13446                 this.fireEvent('edit', this, this.lastData );
13447                 
13448             }, this);
13449         }
13450         */
13451         
13452         this.keyNav = new Roo.KeyNav(this.inputEl(), {
13453             "up" : function(e){
13454                 this.inKeyMode = true;
13455                 this.selectPrev();
13456             },
13457
13458             "down" : function(e){
13459                 if(!this.isExpanded()){
13460                     this.onTriggerClick();
13461                 }else{
13462                     this.inKeyMode = true;
13463                     this.selectNext();
13464                 }
13465             },
13466
13467             "enter" : function(e){
13468 //                this.onViewClick();
13469                 //return true;
13470                 this.collapse();
13471                 
13472                 if(this.fireEvent("specialkey", this, e)){
13473                     this.onViewClick(false);
13474                 }
13475                 
13476                 return true;
13477             },
13478
13479             "esc" : function(e){
13480                 this.collapse();
13481             },
13482
13483             "tab" : function(e){
13484                 this.collapse();
13485                 
13486                 if(this.fireEvent("specialkey", this, e)){
13487                     this.onViewClick(false);
13488                 }
13489                 
13490                 return true;
13491             },
13492
13493             scope : this,
13494
13495             doRelay : function(foo, bar, hname){
13496                 if(hname == 'down' || this.scope.isExpanded()){
13497                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13498                 }
13499                 return true;
13500             },
13501
13502             forceKeyDown: true
13503         });
13504         
13505         
13506         this.queryDelay = Math.max(this.queryDelay || 10,
13507                 this.mode == 'local' ? 10 : 250);
13508         
13509         
13510         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13511         
13512         if(this.typeAhead){
13513             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13514         }
13515         if(this.editable !== false){
13516             this.inputEl().on("keyup", this.onKeyUp, this);
13517         }
13518         if(this.forceSelection){
13519             this.inputEl().on('blur', this.doForce, this);
13520         }
13521         
13522         if(this.multiple){
13523             this.choices = this.el.select('ul.roo-select2-choices', true).first();
13524             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13525         }
13526     },
13527     
13528     initTickableEvents: function()
13529     {   
13530         this.createList();
13531         
13532         if(this.hiddenName){
13533             
13534             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13535             
13536             this.hiddenField.dom.value =
13537                 this.hiddenValue !== undefined ? this.hiddenValue :
13538                 this.value !== undefined ? this.value : '';
13539
13540             // prevent input submission
13541             this.el.dom.removeAttribute('name');
13542             this.hiddenField.dom.setAttribute('name', this.hiddenName);
13543              
13544              
13545         }
13546         
13547 //        this.list = this.el.select('ul.dropdown-menu',true).first();
13548         
13549         this.choices = this.el.select('ul.roo-select2-choices', true).first();
13550         this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13551         if(this.triggerList){
13552             this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13553         }
13554          
13555         this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13556         this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13557         
13558         this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13559         this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13560         
13561         this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13562         this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13563         
13564         this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13565         this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13566         this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13567         
13568         this.okBtn.hide();
13569         this.cancelBtn.hide();
13570         
13571         var _this = this;
13572         
13573         (function(){
13574             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13575             _this.list.setWidth(lw);
13576         }).defer(100);
13577         
13578         this.list.on('mouseover', this.onViewOver, this);
13579         this.list.on('mousemove', this.onViewMove, this);
13580         
13581         this.list.on('scroll', this.onViewScroll, this);
13582         
13583         if(!this.tpl){
13584             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>';
13585         }
13586
13587         this.view = new Roo.View(this.list, this.tpl, {
13588             singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
13589         });
13590         
13591         //this.view.wrapEl.setDisplayed(false);
13592         this.view.on('click', this.onViewClick, this);
13593         
13594         
13595         
13596         this.store.on('beforeload', this.onBeforeLoad, this);
13597         this.store.on('load', this.onLoad, this);
13598         this.store.on('loadexception', this.onLoadException, this);
13599         
13600         if(this.editable){
13601             this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13602                 "up" : function(e){
13603                     this.inKeyMode = true;
13604                     this.selectPrev();
13605                 },
13606
13607                 "down" : function(e){
13608                     this.inKeyMode = true;
13609                     this.selectNext();
13610                 },
13611
13612                 "enter" : function(e){
13613                     if(this.fireEvent("specialkey", this, e)){
13614                         this.onViewClick(false);
13615                     }
13616                     
13617                     return true;
13618                 },
13619
13620                 "esc" : function(e){
13621                     this.onTickableFooterButtonClick(e, false, false);
13622                 },
13623
13624                 "tab" : function(e){
13625                     this.fireEvent("specialkey", this, e);
13626                     
13627                     this.onTickableFooterButtonClick(e, false, false);
13628                     
13629                     return true;
13630                 },
13631
13632                 scope : this,
13633
13634                 doRelay : function(e, fn, key){
13635                     if(this.scope.isExpanded()){
13636                        return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13637                     }
13638                     return true;
13639                 },
13640
13641                 forceKeyDown: true
13642             });
13643         }
13644         
13645         this.queryDelay = Math.max(this.queryDelay || 10,
13646                 this.mode == 'local' ? 10 : 250);
13647         
13648         
13649         this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13650         
13651         if(this.typeAhead){
13652             this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13653         }
13654         
13655         if(this.editable !== false){
13656             this.tickableInputEl().on("keyup", this.onKeyUp, this);
13657         }
13658         
13659         this.indicator = this.indicatorEl();
13660         
13661         if(this.indicator){
13662             this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13663             this.indicator.hide();
13664         }
13665         
13666     },
13667
13668     onDestroy : function(){
13669         if(this.view){
13670             this.view.setStore(null);
13671             this.view.el.removeAllListeners();
13672             this.view.el.remove();
13673             this.view.purgeListeners();
13674         }
13675         if(this.list){
13676             this.list.dom.innerHTML  = '';
13677         }
13678         
13679         if(this.store){
13680             this.store.un('beforeload', this.onBeforeLoad, this);
13681             this.store.un('load', this.onLoad, this);
13682             this.store.un('loadexception', this.onLoadException, this);
13683         }
13684         Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13685     },
13686
13687     // private
13688     fireKey : function(e){
13689         if(e.isNavKeyPress() && !this.list.isVisible()){
13690             this.fireEvent("specialkey", this, e);
13691         }
13692     },
13693
13694     // private
13695     onResize: function(w, h){
13696 //        Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13697 //        
13698 //        if(typeof w != 'number'){
13699 //            // we do not handle it!?!?
13700 //            return;
13701 //        }
13702 //        var tw = this.trigger.getWidth();
13703 //       // tw += this.addicon ? this.addicon.getWidth() : 0;
13704 //       // tw += this.editicon ? this.editicon.getWidth() : 0;
13705 //        var x = w - tw;
13706 //        this.inputEl().setWidth( this.adjustWidth('input', x));
13707 //            
13708 //        //this.trigger.setStyle('left', x+'px');
13709 //        
13710 //        if(this.list && this.listWidth === undefined){
13711 //            var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13712 //            this.list.setWidth(lw);
13713 //            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13714 //        }
13715         
13716     
13717         
13718     },
13719
13720     /**
13721      * Allow or prevent the user from directly editing the field text.  If false is passed,
13722      * the user will only be able to select from the items defined in the dropdown list.  This method
13723      * is the runtime equivalent of setting the 'editable' config option at config time.
13724      * @param {Boolean} value True to allow the user to directly edit the field text
13725      */
13726     setEditable : function(value){
13727         if(value == this.editable){
13728             return;
13729         }
13730         this.editable = value;
13731         if(!value){
13732             this.inputEl().dom.setAttribute('readOnly', true);
13733             this.inputEl().on('mousedown', this.onTriggerClick,  this);
13734             this.inputEl().addClass('x-combo-noedit');
13735         }else{
13736             this.inputEl().dom.setAttribute('readOnly', false);
13737             this.inputEl().un('mousedown', this.onTriggerClick,  this);
13738             this.inputEl().removeClass('x-combo-noedit');
13739         }
13740     },
13741
13742     // private
13743     
13744     onBeforeLoad : function(combo,opts){
13745         if(!this.hasFocus){
13746             return;
13747         }
13748          if (!opts.add) {
13749             this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
13750          }
13751         this.restrictHeight();
13752         this.selectedIndex = -1;
13753     },
13754
13755     // private
13756     onLoad : function(){
13757         
13758         this.hasQuery = false;
13759         
13760         if(!this.hasFocus){
13761             return;
13762         }
13763         
13764         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13765             this.loading.hide();
13766         }
13767         
13768         if(this.store.getCount() > 0){
13769             
13770             this.expand();
13771             this.restrictHeight();
13772             if(this.lastQuery == this.allQuery){
13773                 if(this.editable && !this.tickable){
13774                     this.inputEl().dom.select();
13775                 }
13776                 
13777                 if(
13778                     !this.selectByValue(this.value, true) &&
13779                     this.autoFocus && 
13780                     (
13781                         !this.store.lastOptions ||
13782                         typeof(this.store.lastOptions.add) == 'undefined' || 
13783                         this.store.lastOptions.add != true
13784                     )
13785                 ){
13786                     this.select(0, true);
13787                 }
13788             }else{
13789                 if(this.autoFocus){
13790                     this.selectNext();
13791                 }
13792                 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
13793                     this.taTask.delay(this.typeAheadDelay);
13794                 }
13795             }
13796         }else{
13797             this.onEmptyResults();
13798         }
13799         
13800         //this.el.focus();
13801     },
13802     // private
13803     onLoadException : function()
13804     {
13805         this.hasQuery = false;
13806         
13807         if(typeof(this.loading) !== 'undefined' && this.loading !== null){
13808             this.loading.hide();
13809         }
13810         
13811         if(this.tickable && this.editable){
13812             return;
13813         }
13814         
13815         this.collapse();
13816         // only causes errors at present
13817         //Roo.log(this.store.reader.jsonData);
13818         //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
13819             // fixme
13820             //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
13821         //}
13822         
13823         
13824     },
13825     // private
13826     onTypeAhead : function(){
13827         if(this.store.getCount() > 0){
13828             var r = this.store.getAt(0);
13829             var newValue = r.data[this.displayField];
13830             var len = newValue.length;
13831             var selStart = this.getRawValue().length;
13832             
13833             if(selStart != len){
13834                 this.setRawValue(newValue);
13835                 this.selectText(selStart, newValue.length);
13836             }
13837         }
13838     },
13839
13840     // private
13841     onSelect : function(record, index){
13842         
13843         if(this.fireEvent('beforeselect', this, record, index) !== false){
13844         
13845             this.setFromData(index > -1 ? record.data : false);
13846             
13847             this.collapse();
13848             this.fireEvent('select', this, record, index);
13849         }
13850     },
13851
13852     /**
13853      * Returns the currently selected field value or empty string if no value is set.
13854      * @return {String} value The selected value
13855      */
13856     getValue : function()
13857     {
13858         if(Roo.isIOS && this.useNativeIOS){
13859             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
13860         }
13861         
13862         if(this.multiple){
13863             return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
13864         }
13865         
13866         if(this.valueField){
13867             return typeof this.value != 'undefined' ? this.value : '';
13868         }else{
13869             return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
13870         }
13871     },
13872     
13873     getRawValue : function()
13874     {
13875         if(Roo.isIOS && this.useNativeIOS){
13876             return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
13877         }
13878         
13879         var v = this.inputEl().getValue();
13880         
13881         return v;
13882     },
13883
13884     /**
13885      * Clears any text/value currently set in the field
13886      */
13887     clearValue : function(){
13888         
13889         if(this.hiddenField){
13890             this.hiddenField.dom.value = '';
13891         }
13892         this.value = '';
13893         this.setRawValue('');
13894         this.lastSelectionText = '';
13895         this.lastData = false;
13896         
13897         var close = this.closeTriggerEl();
13898         
13899         if(close){
13900             close.hide();
13901         }
13902         
13903         this.validate();
13904         
13905     },
13906
13907     /**
13908      * Sets the specified value into the field.  If the value finds a match, the corresponding record text
13909      * will be displayed in the field.  If the value does not match the data value of an existing item,
13910      * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
13911      * Otherwise the field will be blank (although the value will still be set).
13912      * @param {String} value The value to match
13913      */
13914     setValue : function(v)
13915     {
13916         if(Roo.isIOS && this.useNativeIOS){
13917             this.setIOSValue(v);
13918             return;
13919         }
13920         
13921         if(this.multiple){
13922             this.syncValue();
13923             return;
13924         }
13925         
13926         var text = v;
13927         if(this.valueField){
13928             var r = this.findRecord(this.valueField, v);
13929             if(r){
13930                 text = r.data[this.displayField];
13931             }else if(this.valueNotFoundText !== undefined){
13932                 text = this.valueNotFoundText;
13933             }
13934         }
13935         this.lastSelectionText = text;
13936         if(this.hiddenField){
13937             this.hiddenField.dom.value = v;
13938         }
13939         Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
13940         this.value = v;
13941         
13942         var close = this.closeTriggerEl();
13943         
13944         if(close){
13945             (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
13946         }
13947         
13948         this.validate();
13949     },
13950     /**
13951      * @property {Object} the last set data for the element
13952      */
13953     
13954     lastData : false,
13955     /**
13956      * Sets the value of the field based on a object which is related to the record format for the store.
13957      * @param {Object} value the value to set as. or false on reset?
13958      */
13959     setFromData : function(o){
13960         
13961         if(this.multiple){
13962             this.addItem(o);
13963             return;
13964         }
13965             
13966         var dv = ''; // display value
13967         var vv = ''; // value value..
13968         this.lastData = o;
13969         if (this.displayField) {
13970             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
13971         } else {
13972             // this is an error condition!!!
13973             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
13974         }
13975         
13976         if(this.valueField){
13977             vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
13978         }
13979         
13980         var close = this.closeTriggerEl();
13981         
13982         if(close){
13983             if(dv.length || vv * 1 > 0){
13984                 close.show() ;
13985                 this.blockFocus=true;
13986             } else {
13987                 close.hide();
13988             }             
13989         }
13990         
13991         if(this.hiddenField){
13992             this.hiddenField.dom.value = vv;
13993             
13994             this.lastSelectionText = dv;
13995             Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
13996             this.value = vv;
13997             return;
13998         }
13999         // no hidden field.. - we store the value in 'value', but still display
14000         // display field!!!!
14001         this.lastSelectionText = dv;
14002         Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14003         this.value = vv;
14004         
14005         
14006         
14007     },
14008     // private
14009     reset : function(){
14010         // overridden so that last data is reset..
14011         
14012         if(this.multiple){
14013             this.clearItem();
14014             return;
14015         }
14016         
14017         this.setValue(this.originalValue);
14018         //this.clearInvalid();
14019         this.lastData = false;
14020         if (this.view) {
14021             this.view.clearSelections();
14022         }
14023         
14024         this.validate();
14025     },
14026     // private
14027     findRecord : function(prop, value){
14028         var record;
14029         if(this.store.getCount() > 0){
14030             this.store.each(function(r){
14031                 if(r.data[prop] == value){
14032                     record = r;
14033                     return false;
14034                 }
14035                 return true;
14036             });
14037         }
14038         return record;
14039     },
14040     
14041     getName: function()
14042     {
14043         // returns hidden if it's set..
14044         if (!this.rendered) {return ''};
14045         return !this.hiddenName && this.inputEl().dom.name  ? this.inputEl().dom.name : (this.hiddenName || '');
14046         
14047     },
14048     // private
14049     onViewMove : function(e, t){
14050         this.inKeyMode = false;
14051     },
14052
14053     // private
14054     onViewOver : function(e, t){
14055         if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14056             return;
14057         }
14058         var item = this.view.findItemFromChild(t);
14059         
14060         if(item){
14061             var index = this.view.indexOf(item);
14062             this.select(index, false);
14063         }
14064     },
14065
14066     // private
14067     onViewClick : function(view, doFocus, el, e)
14068     {
14069         var index = this.view.getSelectedIndexes()[0];
14070         
14071         var r = this.store.getAt(index);
14072         
14073         if(this.tickable){
14074             
14075             if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14076                 return;
14077             }
14078             
14079             var rm = false;
14080             var _this = this;
14081             
14082             Roo.each(this.tickItems, function(v,k){
14083                 
14084                 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14085                     Roo.log(v);
14086                     _this.tickItems.splice(k, 1);
14087                     
14088                     if(typeof(e) == 'undefined' && view == false){
14089                         Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14090                     }
14091                     
14092                     rm = true;
14093                     return;
14094                 }
14095             });
14096             
14097             if(rm){
14098                 return;
14099             }
14100             
14101             if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14102                 this.tickItems.push(r.data);
14103             }
14104             
14105             if(typeof(e) == 'undefined' && view == false){
14106                 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14107             }
14108                     
14109             return;
14110         }
14111         
14112         if(r){
14113             this.onSelect(r, index);
14114         }
14115         if(doFocus !== false && !this.blockFocus){
14116             this.inputEl().focus();
14117         }
14118     },
14119
14120     // private
14121     restrictHeight : function(){
14122         //this.innerList.dom.style.height = '';
14123         //var inner = this.innerList.dom;
14124         //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14125         //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14126         //this.list.beginUpdate();
14127         //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14128         this.list.alignTo(this.inputEl(), this.listAlign);
14129         this.list.alignTo(this.inputEl(), this.listAlign);
14130         //this.list.endUpdate();
14131     },
14132
14133     // private
14134     onEmptyResults : function(){
14135         
14136         if(this.tickable && this.editable){
14137             this.hasFocus = false;
14138             this.restrictHeight();
14139             return;
14140         }
14141         
14142         this.collapse();
14143     },
14144
14145     /**
14146      * Returns true if the dropdown list is expanded, else false.
14147      */
14148     isExpanded : function(){
14149         return this.list.isVisible();
14150     },
14151
14152     /**
14153      * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14154      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14155      * @param {String} value The data value of the item to select
14156      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14157      * selected item if it is not currently in view (defaults to true)
14158      * @return {Boolean} True if the value matched an item in the list, else false
14159      */
14160     selectByValue : function(v, scrollIntoView){
14161         if(v !== undefined && v !== null){
14162             var r = this.findRecord(this.valueField || this.displayField, v);
14163             if(r){
14164                 this.select(this.store.indexOf(r), scrollIntoView);
14165                 return true;
14166             }
14167         }
14168         return false;
14169     },
14170
14171     /**
14172      * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14173      * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14174      * @param {Number} index The zero-based index of the list item to select
14175      * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14176      * selected item if it is not currently in view (defaults to true)
14177      */
14178     select : function(index, scrollIntoView){
14179         this.selectedIndex = index;
14180         this.view.select(index);
14181         if(scrollIntoView !== false){
14182             var el = this.view.getNode(index);
14183             /*
14184              * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14185              */
14186             if(el){
14187                 this.list.scrollChildIntoView(el, false);
14188             }
14189         }
14190     },
14191
14192     // private
14193     selectNext : function(){
14194         var ct = this.store.getCount();
14195         if(ct > 0){
14196             if(this.selectedIndex == -1){
14197                 this.select(0);
14198             }else if(this.selectedIndex < ct-1){
14199                 this.select(this.selectedIndex+1);
14200             }
14201         }
14202     },
14203
14204     // private
14205     selectPrev : function(){
14206         var ct = this.store.getCount();
14207         if(ct > 0){
14208             if(this.selectedIndex == -1){
14209                 this.select(0);
14210             }else if(this.selectedIndex != 0){
14211                 this.select(this.selectedIndex-1);
14212             }
14213         }
14214     },
14215
14216     // private
14217     onKeyUp : function(e){
14218         if(this.editable !== false && !e.isSpecialKey()){
14219             this.lastKey = e.getKey();
14220             this.dqTask.delay(this.queryDelay);
14221         }
14222     },
14223
14224     // private
14225     validateBlur : function(){
14226         return !this.list || !this.list.isVisible();   
14227     },
14228
14229     // private
14230     initQuery : function(){
14231         
14232         var v = this.getRawValue();
14233         
14234         if(this.tickable && this.editable){
14235             v = this.tickableInputEl().getValue();
14236         }
14237         
14238         this.doQuery(v);
14239     },
14240
14241     // private
14242     doForce : function(){
14243         if(this.inputEl().dom.value.length > 0){
14244             this.inputEl().dom.value =
14245                 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14246              
14247         }
14248     },
14249
14250     /**
14251      * Execute a query to filter the dropdown list.  Fires the beforequery event prior to performing the
14252      * query allowing the query action to be canceled if needed.
14253      * @param {String} query The SQL query to execute
14254      * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14255      * in the field than the minimum specified by the minChars config option.  It also clears any filter previously
14256      * saved in the current store (defaults to false)
14257      */
14258     doQuery : function(q, forceAll){
14259         
14260         if(q === undefined || q === null){
14261             q = '';
14262         }
14263         var qe = {
14264             query: q,
14265             forceAll: forceAll,
14266             combo: this,
14267             cancel:false
14268         };
14269         if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14270             return false;
14271         }
14272         q = qe.query;
14273         
14274         forceAll = qe.forceAll;
14275         if(forceAll === true || (q.length >= this.minChars)){
14276             
14277             this.hasQuery = true;
14278             
14279             if(this.lastQuery != q || this.alwaysQuery){
14280                 this.lastQuery = q;
14281                 if(this.mode == 'local'){
14282                     this.selectedIndex = -1;
14283                     if(forceAll){
14284                         this.store.clearFilter();
14285                     }else{
14286                         
14287                         if(this.specialFilter){
14288                             this.fireEvent('specialfilter', this);
14289                             this.onLoad();
14290                             return;
14291                         }
14292                         
14293                         this.store.filter(this.displayField, q);
14294                     }
14295                     
14296                     this.store.fireEvent("datachanged", this.store);
14297                     
14298                     this.onLoad();
14299                     
14300                     
14301                 }else{
14302                     
14303                     this.store.baseParams[this.queryParam] = q;
14304                     
14305                     var options = {params : this.getParams(q)};
14306                     
14307                     if(this.loadNext){
14308                         options.add = true;
14309                         options.params.start = this.page * this.pageSize;
14310                     }
14311                     
14312                     this.store.load(options);
14313                     
14314                     /*
14315                      *  this code will make the page width larger, at the beginning, the list not align correctly, 
14316                      *  we should expand the list on onLoad
14317                      *  so command out it
14318                      */
14319 //                    this.expand();
14320                 }
14321             }else{
14322                 this.selectedIndex = -1;
14323                 this.onLoad();   
14324             }
14325         }
14326         
14327         this.loadNext = false;
14328     },
14329     
14330     // private
14331     getParams : function(q){
14332         var p = {};
14333         //p[this.queryParam] = q;
14334         
14335         if(this.pageSize){
14336             p.start = 0;
14337             p.limit = this.pageSize;
14338         }
14339         return p;
14340     },
14341
14342     /**
14343      * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14344      */
14345     collapse : function(){
14346         if(!this.isExpanded()){
14347             return;
14348         }
14349         
14350         this.list.hide();
14351         
14352         this.hasFocus = false;
14353         
14354         if(this.tickable){
14355             this.okBtn.hide();
14356             this.cancelBtn.hide();
14357             this.trigger.show();
14358             
14359             if(this.editable){
14360                 this.tickableInputEl().dom.value = '';
14361                 this.tickableInputEl().blur();
14362             }
14363             
14364         }
14365         
14366         Roo.get(document).un('mousedown', this.collapseIf, this);
14367         Roo.get(document).un('mousewheel', this.collapseIf, this);
14368         if (!this.editable) {
14369             Roo.get(document).un('keydown', this.listKeyPress, this);
14370         }
14371         this.fireEvent('collapse', this);
14372         
14373         this.validate();
14374     },
14375
14376     // private
14377     collapseIf : function(e){
14378         var in_combo  = e.within(this.el);
14379         var in_list =  e.within(this.list);
14380         var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14381         
14382         if (in_combo || in_list || is_list) {
14383             //e.stopPropagation();
14384             return;
14385         }
14386         
14387         if(this.tickable){
14388             this.onTickableFooterButtonClick(e, false, false);
14389         }
14390
14391         this.collapse();
14392         
14393     },
14394
14395     /**
14396      * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14397      */
14398     expand : function(){
14399        
14400         if(this.isExpanded() || !this.hasFocus){
14401             return;
14402         }
14403         
14404         var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14405         this.list.setWidth(lw);
14406         
14407         Roo.log('expand');
14408         
14409         this.list.show();
14410         
14411         this.restrictHeight();
14412         
14413         if(this.tickable){
14414             
14415             this.tickItems = Roo.apply([], this.item);
14416             
14417             this.okBtn.show();
14418             this.cancelBtn.show();
14419             this.trigger.hide();
14420             
14421             if(this.editable){
14422                 this.tickableInputEl().focus();
14423             }
14424             
14425         }
14426         
14427         Roo.get(document).on('mousedown', this.collapseIf, this);
14428         Roo.get(document).on('mousewheel', this.collapseIf, this);
14429         if (!this.editable) {
14430             Roo.get(document).on('keydown', this.listKeyPress, this);
14431         }
14432         
14433         this.fireEvent('expand', this);
14434     },
14435
14436     // private
14437     // Implements the default empty TriggerField.onTriggerClick function
14438     onTriggerClick : function(e)
14439     {
14440         Roo.log('trigger click');
14441         
14442         if(this.disabled || !this.triggerList){
14443             return;
14444         }
14445         
14446         this.page = 0;
14447         this.loadNext = false;
14448         
14449         if(this.isExpanded()){
14450             this.collapse();
14451             if (!this.blockFocus) {
14452                 this.inputEl().focus();
14453             }
14454             
14455         }else {
14456             this.hasFocus = true;
14457             if(this.triggerAction == 'all') {
14458                 this.doQuery(this.allQuery, true);
14459             } else {
14460                 this.doQuery(this.getRawValue());
14461             }
14462             if (!this.blockFocus) {
14463                 this.inputEl().focus();
14464             }
14465         }
14466     },
14467     
14468     onTickableTriggerClick : function(e)
14469     {
14470         if(this.disabled){
14471             return;
14472         }
14473         
14474         this.page = 0;
14475         this.loadNext = false;
14476         this.hasFocus = true;
14477         
14478         if(this.triggerAction == 'all') {
14479             this.doQuery(this.allQuery, true);
14480         } else {
14481             this.doQuery(this.getRawValue());
14482         }
14483     },
14484     
14485     onSearchFieldClick : function(e)
14486     {
14487         if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14488             this.onTickableFooterButtonClick(e, false, false);
14489             return;
14490         }
14491         
14492         if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14493             return;
14494         }
14495         
14496         this.page = 0;
14497         this.loadNext = false;
14498         this.hasFocus = true;
14499         
14500         if(this.triggerAction == 'all') {
14501             this.doQuery(this.allQuery, true);
14502         } else {
14503             this.doQuery(this.getRawValue());
14504         }
14505     },
14506     
14507     listKeyPress : function(e)
14508     {
14509         //Roo.log('listkeypress');
14510         // scroll to first matching element based on key pres..
14511         if (e.isSpecialKey()) {
14512             return false;
14513         }
14514         var k = String.fromCharCode(e.getKey()).toUpperCase();
14515         //Roo.log(k);
14516         var match  = false;
14517         var csel = this.view.getSelectedNodes();
14518         var cselitem = false;
14519         if (csel.length) {
14520             var ix = this.view.indexOf(csel[0]);
14521             cselitem  = this.store.getAt(ix);
14522             if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14523                 cselitem = false;
14524             }
14525             
14526         }
14527         
14528         this.store.each(function(v) { 
14529             if (cselitem) {
14530                 // start at existing selection.
14531                 if (cselitem.id == v.id) {
14532                     cselitem = false;
14533                 }
14534                 return true;
14535             }
14536                 
14537             if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14538                 match = this.store.indexOf(v);
14539                 return false;
14540             }
14541             return true;
14542         }, this);
14543         
14544         if (match === false) {
14545             return true; // no more action?
14546         }
14547         // scroll to?
14548         this.view.select(match);
14549         var sn = Roo.get(this.view.getSelectedNodes()[0]);
14550         sn.scrollIntoView(sn.dom.parentNode, false);
14551     },
14552     
14553     onViewScroll : function(e, t){
14554         
14555         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){
14556             return;
14557         }
14558         
14559         this.hasQuery = true;
14560         
14561         this.loading = this.list.select('.loading', true).first();
14562         
14563         if(this.loading === null){
14564             this.list.createChild({
14565                 tag: 'div',
14566                 cls: 'loading roo-select2-more-results roo-select2-active',
14567                 html: 'Loading more results...'
14568             });
14569             
14570             this.loading = this.list.select('.loading', true).first();
14571             
14572             this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14573             
14574             this.loading.hide();
14575         }
14576         
14577         this.loading.show();
14578         
14579         var _combo = this;
14580         
14581         this.page++;
14582         this.loadNext = true;
14583         
14584         (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14585         
14586         return;
14587     },
14588     
14589     addItem : function(o)
14590     {   
14591         var dv = ''; // display value
14592         
14593         if (this.displayField) {
14594             dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14595         } else {
14596             // this is an error condition!!!
14597             Roo.log('no  displayField value set for '+ (this.name ? this.name : this.id));
14598         }
14599         
14600         if(!dv.length){
14601             return;
14602         }
14603         
14604         var choice = this.choices.createChild({
14605             tag: 'li',
14606             cls: 'roo-select2-search-choice',
14607             cn: [
14608                 {
14609                     tag: 'div',
14610                     html: dv
14611                 },
14612                 {
14613                     tag: 'a',
14614                     href: '#',
14615                     cls: 'roo-select2-search-choice-close fa fa-times',
14616                     tabindex: '-1'
14617                 }
14618             ]
14619             
14620         }, this.searchField);
14621         
14622         var close = choice.select('a.roo-select2-search-choice-close', true).first();
14623         
14624         close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14625         
14626         this.item.push(o);
14627         
14628         this.lastData = o;
14629         
14630         this.syncValue();
14631         
14632         this.inputEl().dom.value = '';
14633         
14634         this.validate();
14635     },
14636     
14637     onRemoveItem : function(e, _self, o)
14638     {
14639         e.preventDefault();
14640         
14641         this.lastItem = Roo.apply([], this.item);
14642         
14643         var index = this.item.indexOf(o.data) * 1;
14644         
14645         if( index < 0){
14646             Roo.log('not this item?!');
14647             return;
14648         }
14649         
14650         this.item.splice(index, 1);
14651         o.item.remove();
14652         
14653         this.syncValue();
14654         
14655         this.fireEvent('remove', this, e);
14656         
14657         this.validate();
14658         
14659     },
14660     
14661     syncValue : function()
14662     {
14663         if(!this.item.length){
14664             this.clearValue();
14665             return;
14666         }
14667             
14668         var value = [];
14669         var _this = this;
14670         Roo.each(this.item, function(i){
14671             if(_this.valueField){
14672                 value.push(i[_this.valueField]);
14673                 return;
14674             }
14675
14676             value.push(i);
14677         });
14678
14679         this.value = value.join(',');
14680
14681         if(this.hiddenField){
14682             this.hiddenField.dom.value = this.value;
14683         }
14684         
14685         this.store.fireEvent("datachanged", this.store);
14686         
14687         this.validate();
14688     },
14689     
14690     clearItem : function()
14691     {
14692         if(!this.multiple){
14693             return;
14694         }
14695         
14696         this.item = [];
14697         
14698         Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14699            c.remove();
14700         });
14701         
14702         this.syncValue();
14703         
14704         this.validate();
14705         
14706         if(this.tickable && !Roo.isTouch){
14707             this.view.refresh();
14708         }
14709     },
14710     
14711     inputEl: function ()
14712     {
14713         if(Roo.isIOS && this.useNativeIOS){
14714             return this.el.select('select.roo-ios-select', true).first();
14715         }
14716         
14717         if(Roo.isTouch && this.mobileTouchView){
14718             return this.el.select('input.form-control',true).first();
14719         }
14720         
14721         if(this.tickable){
14722             return this.searchField;
14723         }
14724         
14725         return this.el.select('input.form-control',true).first();
14726     },
14727     
14728     onTickableFooterButtonClick : function(e, btn, el)
14729     {
14730         e.preventDefault();
14731         
14732         this.lastItem = Roo.apply([], this.item);
14733         
14734         if(btn && btn.name == 'cancel'){
14735             this.tickItems = Roo.apply([], this.item);
14736             this.collapse();
14737             return;
14738         }
14739         
14740         this.clearItem();
14741         
14742         var _this = this;
14743         
14744         Roo.each(this.tickItems, function(o){
14745             _this.addItem(o);
14746         });
14747         
14748         this.collapse();
14749         
14750     },
14751     
14752     validate : function()
14753     {
14754         if(this.getVisibilityEl().hasClass('hidden')){
14755             return true;
14756         }
14757         
14758         var v = this.getRawValue();
14759         
14760         if(this.multiple){
14761             v = this.getValue();
14762         }
14763         
14764         if(this.disabled || this.allowBlank || v.length){
14765             this.markValid();
14766             return true;
14767         }
14768         
14769         this.markInvalid();
14770         return false;
14771     },
14772     
14773     tickableInputEl : function()
14774     {
14775         if(!this.tickable || !this.editable){
14776             return this.inputEl();
14777         }
14778         
14779         return this.inputEl().select('.roo-select2-search-field-input', true).first();
14780     },
14781     
14782     
14783     getAutoCreateTouchView : function()
14784     {
14785         var id = Roo.id();
14786         
14787         var cfg = {
14788             cls: 'form-group' //input-group
14789         };
14790         
14791         var input =  {
14792             tag: 'input',
14793             id : id,
14794             type : this.inputType,
14795             cls : 'form-control x-combo-noedit',
14796             autocomplete: 'new-password',
14797             placeholder : this.placeholder || '',
14798             readonly : true
14799         };
14800         
14801         if (this.name) {
14802             input.name = this.name;
14803         }
14804         
14805         if (this.size) {
14806             input.cls += ' input-' + this.size;
14807         }
14808         
14809         if (this.disabled) {
14810             input.disabled = true;
14811         }
14812         
14813         var inputblock = {
14814             cls : '',
14815             cn : [
14816                 input
14817             ]
14818         };
14819         
14820         if(this.before){
14821             inputblock.cls += ' input-group';
14822             
14823             inputblock.cn.unshift({
14824                 tag :'span',
14825                 cls : 'input-group-addon',
14826                 html : this.before
14827             });
14828         }
14829         
14830         if(this.removable && !this.multiple){
14831             inputblock.cls += ' roo-removable';
14832             
14833             inputblock.cn.push({
14834                 tag: 'button',
14835                 html : 'x',
14836                 cls : 'roo-combo-removable-btn close'
14837             });
14838         }
14839
14840         if(this.hasFeedback && !this.allowBlank){
14841             
14842             inputblock.cls += ' has-feedback';
14843             
14844             inputblock.cn.push({
14845                 tag: 'span',
14846                 cls: 'glyphicon form-control-feedback'
14847             });
14848             
14849         }
14850         
14851         if (this.after) {
14852             
14853             inputblock.cls += (this.before) ? '' : ' input-group';
14854             
14855             inputblock.cn.push({
14856                 tag :'span',
14857                 cls : 'input-group-addon',
14858                 html : this.after
14859             });
14860         }
14861
14862         var box = {
14863             tag: 'div',
14864             cn: [
14865                 {
14866                     tag: 'input',
14867                     type : 'hidden',
14868                     cls: 'form-hidden-field'
14869                 },
14870                 inputblock
14871             ]
14872             
14873         };
14874         
14875         if(this.multiple){
14876             box = {
14877                 tag: 'div',
14878                 cn: [
14879                     {
14880                         tag: 'input',
14881                         type : 'hidden',
14882                         cls: 'form-hidden-field'
14883                     },
14884                     {
14885                         tag: 'ul',
14886                         cls: 'roo-select2-choices',
14887                         cn:[
14888                             {
14889                                 tag: 'li',
14890                                 cls: 'roo-select2-search-field',
14891                                 cn: [
14892
14893                                     inputblock
14894                                 ]
14895                             }
14896                         ]
14897                     }
14898                 ]
14899             }
14900         };
14901         
14902         var combobox = {
14903             cls: 'roo-select2-container input-group roo-touchview-combobox ',
14904             cn: [
14905                 box
14906             ]
14907         };
14908         
14909         if(!this.multiple && this.showToggleBtn){
14910             
14911             var caret = {
14912                         tag: 'span',
14913                         cls: 'caret'
14914             };
14915             
14916             if (this.caret != false) {
14917                 caret = {
14918                      tag: 'i',
14919                      cls: 'fa fa-' + this.caret
14920                 };
14921                 
14922             }
14923             
14924             combobox.cn.push({
14925                 tag :'span',
14926                 cls : 'input-group-addon btn dropdown-toggle',
14927                 cn : [
14928                     caret,
14929                     {
14930                         tag: 'span',
14931                         cls: 'combobox-clear',
14932                         cn  : [
14933                             {
14934                                 tag : 'i',
14935                                 cls: 'icon-remove'
14936                             }
14937                         ]
14938                     }
14939                 ]
14940
14941             })
14942         }
14943         
14944         if(this.multiple){
14945             combobox.cls += ' roo-select2-container-multi';
14946         }
14947         
14948         var align = this.labelAlign || this.parentLabelAlign();
14949         
14950         if (align ==='left' && this.fieldLabel.length) {
14951
14952             cfg.cn = [
14953                 {
14954                    tag : 'i',
14955                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
14956                    tooltip : 'This field is required'
14957                 },
14958                 {
14959                     tag: 'label',
14960                     cls : 'control-label',
14961                     html : this.fieldLabel
14962
14963                 },
14964                 {
14965                     cls : '', 
14966                     cn: [
14967                         combobox
14968                     ]
14969                 }
14970             ];
14971             
14972             var labelCfg = cfg.cn[1];
14973             var contentCfg = cfg.cn[2];
14974             
14975
14976             if(this.indicatorpos == 'right'){
14977                 cfg.cn = [
14978                     {
14979                         tag: 'label',
14980                         'for' :  id,
14981                         cls : 'control-label',
14982                         cn : [
14983                             {
14984                                 tag : 'span',
14985                                 html : this.fieldLabel
14986                             },
14987                             {
14988                                 tag : 'i',
14989                                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
14990                                 tooltip : 'This field is required'
14991                             }
14992                         ]
14993                     },
14994                     {
14995                         cls : "",
14996                         cn: [
14997                             combobox
14998                         ]
14999                     }
15000
15001                 ];
15002                 
15003                 labelCfg = cfg.cn[0];
15004                 contentCfg = cfg.cn[1];
15005             }
15006             
15007            
15008             
15009             if(this.labelWidth > 12){
15010                 labelCfg.style = "width: " + this.labelWidth + 'px';
15011             }
15012             
15013             if(this.labelWidth < 13 && this.labelmd == 0){
15014                 this.labelmd = this.labelWidth;
15015             }
15016             
15017             if(this.labellg > 0){
15018                 labelCfg.cls += ' col-lg-' + this.labellg;
15019                 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15020             }
15021             
15022             if(this.labelmd > 0){
15023                 labelCfg.cls += ' col-md-' + this.labelmd;
15024                 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15025             }
15026             
15027             if(this.labelsm > 0){
15028                 labelCfg.cls += ' col-sm-' + this.labelsm;
15029                 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15030             }
15031             
15032             if(this.labelxs > 0){
15033                 labelCfg.cls += ' col-xs-' + this.labelxs;
15034                 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15035             }
15036                 
15037                 
15038         } else if ( this.fieldLabel.length) {
15039             cfg.cn = [
15040                 {
15041                    tag : 'i',
15042                    cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15043                    tooltip : 'This field is required'
15044                 },
15045                 {
15046                     tag: 'label',
15047                     cls : 'control-label',
15048                     html : this.fieldLabel
15049
15050                 },
15051                 {
15052                     cls : '', 
15053                     cn: [
15054                         combobox
15055                     ]
15056                 }
15057             ];
15058             
15059             if(this.indicatorpos == 'right'){
15060                 cfg.cn = [
15061                     {
15062                         tag: 'label',
15063                         cls : 'control-label',
15064                         html : this.fieldLabel,
15065                         cn : [
15066                             {
15067                                tag : 'i',
15068                                cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15069                                tooltip : 'This field is required'
15070                             }
15071                         ]
15072                     },
15073                     {
15074                         cls : '', 
15075                         cn: [
15076                             combobox
15077                         ]
15078                     }
15079                 ];
15080             }
15081         } else {
15082             cfg.cn = combobox;    
15083         }
15084         
15085         
15086         var settings = this;
15087         
15088         ['xs','sm','md','lg'].map(function(size){
15089             if (settings[size]) {
15090                 cfg.cls += ' col-' + size + '-' + settings[size];
15091             }
15092         });
15093         
15094         return cfg;
15095     },
15096     
15097     initTouchView : function()
15098     {
15099         this.renderTouchView();
15100         
15101         this.touchViewEl.on('scroll', function(){
15102             this.el.dom.scrollTop = 0;
15103         }, this);
15104         
15105         this.originalValue = this.getValue();
15106         
15107         this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15108         
15109         this.inputEl().on("click", this.showTouchView, this);
15110         if (this.triggerEl) {
15111             this.triggerEl.on("click", this.showTouchView, this);
15112         }
15113         
15114         
15115         this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15116         this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15117         
15118         this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15119         
15120         this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15121         this.store.on('load', this.onTouchViewLoad, this);
15122         this.store.on('loadexception', this.onTouchViewLoadException, this);
15123         
15124         if(this.hiddenName){
15125             
15126             this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15127             
15128             this.hiddenField.dom.value =
15129                 this.hiddenValue !== undefined ? this.hiddenValue :
15130                 this.value !== undefined ? this.value : '';
15131         
15132             this.el.dom.removeAttribute('name');
15133             this.hiddenField.dom.setAttribute('name', this.hiddenName);
15134         }
15135         
15136         if(this.multiple){
15137             this.choices = this.el.select('ul.roo-select2-choices', true).first();
15138             this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15139         }
15140         
15141         if(this.removable && !this.multiple){
15142             var close = this.closeTriggerEl();
15143             if(close){
15144                 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15145                 close.on('click', this.removeBtnClick, this, close);
15146             }
15147         }
15148         /*
15149          * fix the bug in Safari iOS8
15150          */
15151         this.inputEl().on("focus", function(e){
15152             document.activeElement.blur();
15153         }, this);
15154         
15155         return;
15156         
15157         
15158     },
15159     
15160     renderTouchView : function()
15161     {
15162         this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15163         this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15164         
15165         this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15166         this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15167         
15168         this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15169         this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15170         this.touchViewBodyEl.setStyle('overflow', 'auto');
15171         
15172         this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15173         this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15174         
15175         this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15176         this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15177         
15178     },
15179     
15180     showTouchView : function()
15181     {
15182         if(this.disabled){
15183             return;
15184         }
15185         
15186         this.touchViewHeaderEl.hide();
15187
15188         if(this.modalTitle.length){
15189             this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15190             this.touchViewHeaderEl.show();
15191         }
15192
15193         this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15194         this.touchViewEl.show();
15195
15196         this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15197         
15198         //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15199         //        Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15200
15201         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15202
15203         if(this.modalTitle.length){
15204             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15205         }
15206         
15207         this.touchViewBodyEl.setHeight(bodyHeight);
15208
15209         if(this.animate){
15210             var _this = this;
15211             (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15212         }else{
15213             this.touchViewEl.addClass('in');
15214         }
15215
15216         this.doTouchViewQuery();
15217         
15218     },
15219     
15220     hideTouchView : function()
15221     {
15222         this.touchViewEl.removeClass('in');
15223
15224         if(this.animate){
15225             var _this = this;
15226             (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15227         }else{
15228             this.touchViewEl.setStyle('display', 'none');
15229         }
15230         
15231     },
15232     
15233     setTouchViewValue : function()
15234     {
15235         if(this.multiple){
15236             this.clearItem();
15237         
15238             var _this = this;
15239
15240             Roo.each(this.tickItems, function(o){
15241                 this.addItem(o);
15242             }, this);
15243         }
15244         
15245         this.hideTouchView();
15246     },
15247     
15248     doTouchViewQuery : function()
15249     {
15250         var qe = {
15251             query: '',
15252             forceAll: true,
15253             combo: this,
15254             cancel:false
15255         };
15256         
15257         if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15258             return false;
15259         }
15260         
15261         if(!this.alwaysQuery || this.mode == 'local'){
15262             this.onTouchViewLoad();
15263             return;
15264         }
15265         
15266         this.store.load();
15267     },
15268     
15269     onTouchViewBeforeLoad : function(combo,opts)
15270     {
15271         return;
15272     },
15273
15274     // private
15275     onTouchViewLoad : function()
15276     {
15277         if(this.store.getCount() < 1){
15278             this.onTouchViewEmptyResults();
15279             return;
15280         }
15281         
15282         this.clearTouchView();
15283         
15284         var rawValue = this.getRawValue();
15285         
15286         var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15287         
15288         this.tickItems = [];
15289         
15290         this.store.data.each(function(d, rowIndex){
15291             var row = this.touchViewListGroup.createChild(template);
15292             
15293             if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15294                 row.addClass(d.data.cls);
15295             }
15296             
15297             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15298                 var cfg = {
15299                     data : d.data,
15300                     html : d.data[this.displayField]
15301                 };
15302                 
15303                 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15304                     row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15305                 }
15306             }
15307             row.removeClass('selected');
15308             if(!this.multiple && this.valueField &&
15309                     typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15310             {
15311                 // radio buttons..
15312                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15313                 row.addClass('selected');
15314             }
15315             
15316             if(this.multiple && this.valueField &&
15317                     typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15318             {
15319                 
15320                 // checkboxes...
15321                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15322                 this.tickItems.push(d.data);
15323             }
15324             
15325             row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15326             
15327         }, this);
15328         
15329         var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15330         
15331         var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15332
15333         if(this.modalTitle.length){
15334             bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15335         }
15336
15337         var listHeight = this.touchViewListGroup.getHeight();
15338         
15339         var _this = this;
15340         
15341         if(firstChecked && listHeight > bodyHeight){
15342             (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15343         }
15344         
15345     },
15346     
15347     onTouchViewLoadException : function()
15348     {
15349         this.hideTouchView();
15350     },
15351     
15352     onTouchViewEmptyResults : function()
15353     {
15354         this.clearTouchView();
15355         
15356         this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15357         
15358         this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15359         
15360     },
15361     
15362     clearTouchView : function()
15363     {
15364         this.touchViewListGroup.dom.innerHTML = '';
15365     },
15366     
15367     onTouchViewClick : function(e, el, o)
15368     {
15369         e.preventDefault();
15370         
15371         var row = o.row;
15372         var rowIndex = o.rowIndex;
15373         
15374         var r = this.store.getAt(rowIndex);
15375         
15376         if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15377             
15378             if(!this.multiple){
15379                 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15380                     c.dom.removeAttribute('checked');
15381                 }, this);
15382
15383                 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15384
15385                 this.setFromData(r.data);
15386
15387                 var close = this.closeTriggerEl();
15388
15389                 if(close){
15390                     close.show();
15391                 }
15392
15393                 this.hideTouchView();
15394
15395                 this.fireEvent('select', this, r, rowIndex);
15396
15397                 return;
15398             }
15399
15400             if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15401                 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15402                 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15403                 return;
15404             }
15405
15406             row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15407             this.addItem(r.data);
15408             this.tickItems.push(r.data);
15409         }
15410     },
15411     
15412     getAutoCreateNativeIOS : function()
15413     {
15414         var cfg = {
15415             cls: 'form-group' //input-group,
15416         };
15417         
15418         var combobox =  {
15419             tag: 'select',
15420             cls : 'roo-ios-select'
15421         };
15422         
15423         if (this.name) {
15424             combobox.name = this.name;
15425         }
15426         
15427         if (this.disabled) {
15428             combobox.disabled = true;
15429         }
15430         
15431         var settings = this;
15432         
15433         ['xs','sm','md','lg'].map(function(size){
15434             if (settings[size]) {
15435                 cfg.cls += ' col-' + size + '-' + settings[size];
15436             }
15437         });
15438         
15439         cfg.cn = combobox;
15440         
15441         return cfg;
15442         
15443     },
15444     
15445     initIOSView : function()
15446     {
15447         this.store.on('load', this.onIOSViewLoad, this);
15448         
15449         return;
15450     },
15451     
15452     onIOSViewLoad : function()
15453     {
15454         if(this.store.getCount() < 1){
15455             return;
15456         }
15457         
15458         this.clearIOSView();
15459         
15460         if(this.allowBlank) {
15461             
15462             var default_text = '-- SELECT --';
15463             
15464             if(this.placeholder.length){
15465                 default_text = this.placeholder;
15466             }
15467             
15468             if(this.emptyTitle.length){
15469                 default_text += ' - ' + this.emptyTitle + ' -';
15470             }
15471             
15472             var opt = this.inputEl().createChild({
15473                 tag: 'option',
15474                 value : 0,
15475                 html : default_text
15476             });
15477             
15478             var o = {};
15479             o[this.valueField] = 0;
15480             o[this.displayField] = default_text;
15481             
15482             this.ios_options.push({
15483                 data : o,
15484                 el : opt
15485             });
15486             
15487         }
15488         
15489         this.store.data.each(function(d, rowIndex){
15490             
15491             var html = '';
15492             
15493             if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15494                 html = d.data[this.displayField];
15495             }
15496             
15497             var value = '';
15498             
15499             if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15500                 value = d.data[this.valueField];
15501             }
15502             
15503             var option = {
15504                 tag: 'option',
15505                 value : value,
15506                 html : html
15507             };
15508             
15509             if(this.value == d.data[this.valueField]){
15510                 option['selected'] = true;
15511             }
15512             
15513             var opt = this.inputEl().createChild(option);
15514             
15515             this.ios_options.push({
15516                 data : d.data,
15517                 el : opt
15518             });
15519             
15520         }, this);
15521         
15522         this.inputEl().on('change', function(){
15523            this.fireEvent('select', this);
15524         }, this);
15525         
15526     },
15527     
15528     clearIOSView: function()
15529     {
15530         this.inputEl().dom.innerHTML = '';
15531         
15532         this.ios_options = [];
15533     },
15534     
15535     setIOSValue: function(v)
15536     {
15537         this.value = v;
15538         
15539         if(!this.ios_options){
15540             return;
15541         }
15542         
15543         Roo.each(this.ios_options, function(opts){
15544            
15545            opts.el.dom.removeAttribute('selected');
15546            
15547            if(opts.data[this.valueField] != v){
15548                return;
15549            }
15550            
15551            opts.el.dom.setAttribute('selected', true);
15552            
15553         }, this);
15554     }
15555
15556     /** 
15557     * @cfg {Boolean} grow 
15558     * @hide 
15559     */
15560     /** 
15561     * @cfg {Number} growMin 
15562     * @hide 
15563     */
15564     /** 
15565     * @cfg {Number} growMax 
15566     * @hide 
15567     */
15568     /**
15569      * @hide
15570      * @method autoSize
15571      */
15572 });
15573
15574 Roo.apply(Roo.bootstrap.ComboBox,  {
15575     
15576     header : {
15577         tag: 'div',
15578         cls: 'modal-header',
15579         cn: [
15580             {
15581                 tag: 'h4',
15582                 cls: 'modal-title'
15583             }
15584         ]
15585     },
15586     
15587     body : {
15588         tag: 'div',
15589         cls: 'modal-body',
15590         cn: [
15591             {
15592                 tag: 'ul',
15593                 cls: 'list-group'
15594             }
15595         ]
15596     },
15597     
15598     listItemRadio : {
15599         tag: 'li',
15600         cls: 'list-group-item',
15601         cn: [
15602             {
15603                 tag: 'span',
15604                 cls: 'roo-combobox-list-group-item-value'
15605             },
15606             {
15607                 tag: 'div',
15608                 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15609                 cn: [
15610                     {
15611                         tag: 'input',
15612                         type: 'radio'
15613                     },
15614                     {
15615                         tag: 'label'
15616                     }
15617                 ]
15618             }
15619         ]
15620     },
15621     
15622     listItemCheckbox : {
15623         tag: 'li',
15624         cls: 'list-group-item',
15625         cn: [
15626             {
15627                 tag: 'span',
15628                 cls: 'roo-combobox-list-group-item-value'
15629             },
15630             {
15631                 tag: 'div',
15632                 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15633                 cn: [
15634                     {
15635                         tag: 'input',
15636                         type: 'checkbox'
15637                     },
15638                     {
15639                         tag: 'label'
15640                     }
15641                 ]
15642             }
15643         ]
15644     },
15645     
15646     emptyResult : {
15647         tag: 'div',
15648         cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15649     },
15650     
15651     footer : {
15652         tag: 'div',
15653         cls: 'modal-footer',
15654         cn: [
15655             {
15656                 tag: 'div',
15657                 cls: 'row',
15658                 cn: [
15659                     {
15660                         tag: 'div',
15661                         cls: 'col-xs-6 text-left',
15662                         cn: {
15663                             tag: 'button',
15664                             cls: 'btn btn-danger roo-touch-view-cancel',
15665                             html: 'Cancel'
15666                         }
15667                     },
15668                     {
15669                         tag: 'div',
15670                         cls: 'col-xs-6 text-right',
15671                         cn: {
15672                             tag: 'button',
15673                             cls: 'btn btn-success roo-touch-view-ok',
15674                             html: 'OK'
15675                         }
15676                     }
15677                 ]
15678             }
15679         ]
15680         
15681     }
15682 });
15683
15684 Roo.apply(Roo.bootstrap.ComboBox,  {
15685     
15686     touchViewTemplate : {
15687         tag: 'div',
15688         cls: 'modal fade roo-combobox-touch-view',
15689         cn: [
15690             {
15691                 tag: 'div',
15692                 cls: 'modal-dialog',
15693                 style : 'position:fixed', // we have to fix position....
15694                 cn: [
15695                     {
15696                         tag: 'div',
15697                         cls: 'modal-content',
15698                         cn: [
15699                             Roo.bootstrap.ComboBox.header,
15700                             Roo.bootstrap.ComboBox.body,
15701                             Roo.bootstrap.ComboBox.footer
15702                         ]
15703                     }
15704                 ]
15705             }
15706         ]
15707     }
15708 });/*
15709  * Based on:
15710  * Ext JS Library 1.1.1
15711  * Copyright(c) 2006-2007, Ext JS, LLC.
15712  *
15713  * Originally Released Under LGPL - original licence link has changed is not relivant.
15714  *
15715  * Fork - LGPL
15716  * <script type="text/javascript">
15717  */
15718
15719 /**
15720  * @class Roo.View
15721  * @extends Roo.util.Observable
15722  * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template. 
15723  * This class also supports single and multi selection modes. <br>
15724  * Create a data model bound view:
15725  <pre><code>
15726  var store = new Roo.data.Store(...);
15727
15728  var view = new Roo.View({
15729     el : "my-element",
15730     tpl : '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
15731  
15732     singleSelect: true,
15733     selectedClass: "ydataview-selected",
15734     store: store
15735  });
15736
15737  // listen for node click?
15738  view.on("click", function(vw, index, node, e){
15739  alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
15740  });
15741
15742  // load XML data
15743  dataModel.load("foobar.xml");
15744  </code></pre>
15745  For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
15746  * <br><br>
15747  * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
15748  * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
15749  * 
15750  * Note: old style constructor is still suported (container, template, config)
15751  * 
15752  * @constructor
15753  * Create a new View
15754  * @param {Object} config The config object
15755  * 
15756  */
15757 Roo.View = function(config, depreciated_tpl, depreciated_config){
15758     
15759     this.parent = false;
15760     
15761     if (typeof(depreciated_tpl) == 'undefined') {
15762         // new way.. - universal constructor.
15763         Roo.apply(this, config);
15764         this.el  = Roo.get(this.el);
15765     } else {
15766         // old format..
15767         this.el  = Roo.get(config);
15768         this.tpl = depreciated_tpl;
15769         Roo.apply(this, depreciated_config);
15770     }
15771     this.wrapEl  = this.el.wrap().wrap();
15772     ///this.el = this.wrapEla.appendChild(document.createElement("div"));
15773     
15774     
15775     if(typeof(this.tpl) == "string"){
15776         this.tpl = new Roo.Template(this.tpl);
15777     } else {
15778         // support xtype ctors..
15779         this.tpl = new Roo.factory(this.tpl, Roo);
15780     }
15781     
15782     
15783     this.tpl.compile();
15784     
15785     /** @private */
15786     this.addEvents({
15787         /**
15788          * @event beforeclick
15789          * Fires before a click is processed. Returns false to cancel the default action.
15790          * @param {Roo.View} this
15791          * @param {Number} index The index of the target node
15792          * @param {HTMLElement} node The target node
15793          * @param {Roo.EventObject} e The raw event object
15794          */
15795             "beforeclick" : true,
15796         /**
15797          * @event click
15798          * Fires when a template node is clicked.
15799          * @param {Roo.View} this
15800          * @param {Number} index The index of the target node
15801          * @param {HTMLElement} node The target node
15802          * @param {Roo.EventObject} e The raw event object
15803          */
15804             "click" : true,
15805         /**
15806          * @event dblclick
15807          * Fires when a template node is double clicked.
15808          * @param {Roo.View} this
15809          * @param {Number} index The index of the target node
15810          * @param {HTMLElement} node The target node
15811          * @param {Roo.EventObject} e The raw event object
15812          */
15813             "dblclick" : true,
15814         /**
15815          * @event contextmenu
15816          * Fires when a template node is right clicked.
15817          * @param {Roo.View} this
15818          * @param {Number} index The index of the target node
15819          * @param {HTMLElement} node The target node
15820          * @param {Roo.EventObject} e The raw event object
15821          */
15822             "contextmenu" : true,
15823         /**
15824          * @event selectionchange
15825          * Fires when the selected nodes change.
15826          * @param {Roo.View} this
15827          * @param {Array} selections Array of the selected nodes
15828          */
15829             "selectionchange" : true,
15830     
15831         /**
15832          * @event beforeselect
15833          * Fires before a selection is made. If any handlers return false, the selection is cancelled.
15834          * @param {Roo.View} this
15835          * @param {HTMLElement} node The node to be selected
15836          * @param {Array} selections Array of currently selected nodes
15837          */
15838             "beforeselect" : true,
15839         /**
15840          * @event preparedata
15841          * Fires on every row to render, to allow you to change the data.
15842          * @param {Roo.View} this
15843          * @param {Object} data to be rendered (change this)
15844          */
15845           "preparedata" : true
15846           
15847           
15848         });
15849
15850
15851
15852     this.el.on({
15853         "click": this.onClick,
15854         "dblclick": this.onDblClick,
15855         "contextmenu": this.onContextMenu,
15856         scope:this
15857     });
15858
15859     this.selections = [];
15860     this.nodes = [];
15861     this.cmp = new Roo.CompositeElementLite([]);
15862     if(this.store){
15863         this.store = Roo.factory(this.store, Roo.data);
15864         this.setStore(this.store, true);
15865     }
15866     
15867     if ( this.footer && this.footer.xtype) {
15868            
15869          var fctr = this.wrapEl.appendChild(document.createElement("div"));
15870         
15871         this.footer.dataSource = this.store;
15872         this.footer.container = fctr;
15873         this.footer = Roo.factory(this.footer, Roo);
15874         fctr.insertFirst(this.el);
15875         
15876         // this is a bit insane - as the paging toolbar seems to detach the el..
15877 //        dom.parentNode.parentNode.parentNode
15878          // they get detached?
15879     }
15880     
15881     
15882     Roo.View.superclass.constructor.call(this);
15883     
15884     
15885 };
15886
15887 Roo.extend(Roo.View, Roo.util.Observable, {
15888     
15889      /**
15890      * @cfg {Roo.data.Store} store Data store to load data from.
15891      */
15892     store : false,
15893     
15894     /**
15895      * @cfg {String|Roo.Element} el The container element.
15896      */
15897     el : '',
15898     
15899     /**
15900      * @cfg {String|Roo.Template} tpl The template used by this View 
15901      */
15902     tpl : false,
15903     /**
15904      * @cfg {String} dataName the named area of the template to use as the data area
15905      *                          Works with domtemplates roo-name="name"
15906      */
15907     dataName: false,
15908     /**
15909      * @cfg {String} selectedClass The css class to add to selected nodes
15910      */
15911     selectedClass : "x-view-selected",
15912      /**
15913      * @cfg {String} emptyText The empty text to show when nothing is loaded.
15914      */
15915     emptyText : "",
15916     
15917     /**
15918      * @cfg {String} text to display on mask (default Loading)
15919      */
15920     mask : false,
15921     /**
15922      * @cfg {Boolean} multiSelect Allow multiple selection
15923      */
15924     multiSelect : false,
15925     /**
15926      * @cfg {Boolean} singleSelect Allow single selection
15927      */
15928     singleSelect:  false,
15929     
15930     /**
15931      * @cfg {Boolean} toggleSelect - selecting 
15932      */
15933     toggleSelect : false,
15934     
15935     /**
15936      * @cfg {Boolean} tickable - selecting 
15937      */
15938     tickable : false,
15939     
15940     /**
15941      * Returns the element this view is bound to.
15942      * @return {Roo.Element}
15943      */
15944     getEl : function(){
15945         return this.wrapEl;
15946     },
15947     
15948     
15949
15950     /**
15951      * Refreshes the view. - called by datachanged on the store. - do not call directly.
15952      */
15953     refresh : function(){
15954         //Roo.log('refresh');
15955         var t = this.tpl;
15956         
15957         // if we are using something like 'domtemplate', then
15958         // the what gets used is:
15959         // t.applySubtemplate(NAME, data, wrapping data..)
15960         // the outer template then get' applied with
15961         //     the store 'extra data'
15962         // and the body get's added to the
15963         //      roo-name="data" node?
15964         //      <span class='roo-tpl-{name}'></span> ?????
15965         
15966         
15967         
15968         this.clearSelections();
15969         this.el.update("");
15970         var html = [];
15971         var records = this.store.getRange();
15972         if(records.length < 1) {
15973             
15974             // is this valid??  = should it render a template??
15975             
15976             this.el.update(this.emptyText);
15977             return;
15978         }
15979         var el = this.el;
15980         if (this.dataName) {
15981             this.el.update(t.apply(this.store.meta)); //????
15982             el = this.el.child('.roo-tpl-' + this.dataName);
15983         }
15984         
15985         for(var i = 0, len = records.length; i < len; i++){
15986             var data = this.prepareData(records[i].data, i, records[i]);
15987             this.fireEvent("preparedata", this, data, i, records[i]);
15988             
15989             var d = Roo.apply({}, data);
15990             
15991             if(this.tickable){
15992                 Roo.apply(d, {'roo-id' : Roo.id()});
15993                 
15994                 var _this = this;
15995             
15996                 Roo.each(this.parent.item, function(item){
15997                     if(item[_this.parent.valueField] != data[_this.parent.valueField]){
15998                         return;
15999                     }
16000                     Roo.apply(d, {'roo-data-checked' : 'checked'});
16001                 });
16002             }
16003             
16004             html[html.length] = Roo.util.Format.trim(
16005                 this.dataName ?
16006                     t.applySubtemplate(this.dataName, d, this.store.meta) :
16007                     t.apply(d)
16008             );
16009         }
16010         
16011         
16012         
16013         el.update(html.join(""));
16014         this.nodes = el.dom.childNodes;
16015         this.updateIndexes(0);
16016     },
16017     
16018
16019     /**
16020      * Function to override to reformat the data that is sent to
16021      * the template for each node.
16022      * DEPRICATED - use the preparedata event handler.
16023      * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16024      * a JSON object for an UpdateManager bound view).
16025      */
16026     prepareData : function(data, index, record)
16027     {
16028         this.fireEvent("preparedata", this, data, index, record);
16029         return data;
16030     },
16031
16032     onUpdate : function(ds, record){
16033         // Roo.log('on update');   
16034         this.clearSelections();
16035         var index = this.store.indexOf(record);
16036         var n = this.nodes[index];
16037         this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16038         n.parentNode.removeChild(n);
16039         this.updateIndexes(index, index);
16040     },
16041
16042     
16043     
16044 // --------- FIXME     
16045     onAdd : function(ds, records, index)
16046     {
16047         //Roo.log(['on Add', ds, records, index] );        
16048         this.clearSelections();
16049         if(this.nodes.length == 0){
16050             this.refresh();
16051             return;
16052         }
16053         var n = this.nodes[index];
16054         for(var i = 0, len = records.length; i < len; i++){
16055             var d = this.prepareData(records[i].data, i, records[i]);
16056             if(n){
16057                 this.tpl.insertBefore(n, d);
16058             }else{
16059                 
16060                 this.tpl.append(this.el, d);
16061             }
16062         }
16063         this.updateIndexes(index);
16064     },
16065
16066     onRemove : function(ds, record, index){
16067        // Roo.log('onRemove');
16068         this.clearSelections();
16069         var el = this.dataName  ?
16070             this.el.child('.roo-tpl-' + this.dataName) :
16071             this.el; 
16072         
16073         el.dom.removeChild(this.nodes[index]);
16074         this.updateIndexes(index);
16075     },
16076
16077     /**
16078      * Refresh an individual node.
16079      * @param {Number} index
16080      */
16081     refreshNode : function(index){
16082         this.onUpdate(this.store, this.store.getAt(index));
16083     },
16084
16085     updateIndexes : function(startIndex, endIndex){
16086         var ns = this.nodes;
16087         startIndex = startIndex || 0;
16088         endIndex = endIndex || ns.length - 1;
16089         for(var i = startIndex; i <= endIndex; i++){
16090             ns[i].nodeIndex = i;
16091         }
16092     },
16093
16094     /**
16095      * Changes the data store this view uses and refresh the view.
16096      * @param {Store} store
16097      */
16098     setStore : function(store, initial){
16099         if(!initial && this.store){
16100             this.store.un("datachanged", this.refresh);
16101             this.store.un("add", this.onAdd);
16102             this.store.un("remove", this.onRemove);
16103             this.store.un("update", this.onUpdate);
16104             this.store.un("clear", this.refresh);
16105             this.store.un("beforeload", this.onBeforeLoad);
16106             this.store.un("load", this.onLoad);
16107             this.store.un("loadexception", this.onLoad);
16108         }
16109         if(store){
16110           
16111             store.on("datachanged", this.refresh, this);
16112             store.on("add", this.onAdd, this);
16113             store.on("remove", this.onRemove, this);
16114             store.on("update", this.onUpdate, this);
16115             store.on("clear", this.refresh, this);
16116             store.on("beforeload", this.onBeforeLoad, this);
16117             store.on("load", this.onLoad, this);
16118             store.on("loadexception", this.onLoad, this);
16119         }
16120         
16121         if(store){
16122             this.refresh();
16123         }
16124     },
16125     /**
16126      * onbeforeLoad - masks the loading area.
16127      *
16128      */
16129     onBeforeLoad : function(store,opts)
16130     {
16131          //Roo.log('onBeforeLoad');   
16132         if (!opts.add) {
16133             this.el.update("");
16134         }
16135         this.el.mask(this.mask ? this.mask : "Loading" ); 
16136     },
16137     onLoad : function ()
16138     {
16139         this.el.unmask();
16140     },
16141     
16142
16143     /**
16144      * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16145      * @param {HTMLElement} node
16146      * @return {HTMLElement} The template node
16147      */
16148     findItemFromChild : function(node){
16149         var el = this.dataName  ?
16150             this.el.child('.roo-tpl-' + this.dataName,true) :
16151             this.el.dom; 
16152         
16153         if(!node || node.parentNode == el){
16154                     return node;
16155             }
16156             var p = node.parentNode;
16157             while(p && p != el){
16158             if(p.parentNode == el){
16159                 return p;
16160             }
16161             p = p.parentNode;
16162         }
16163             return null;
16164     },
16165
16166     /** @ignore */
16167     onClick : function(e){
16168         var item = this.findItemFromChild(e.getTarget());
16169         if(item){
16170             var index = this.indexOf(item);
16171             if(this.onItemClick(item, index, e) !== false){
16172                 this.fireEvent("click", this, index, item, e);
16173             }
16174         }else{
16175             this.clearSelections();
16176         }
16177     },
16178
16179     /** @ignore */
16180     onContextMenu : function(e){
16181         var item = this.findItemFromChild(e.getTarget());
16182         if(item){
16183             this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16184         }
16185     },
16186
16187     /** @ignore */
16188     onDblClick : function(e){
16189         var item = this.findItemFromChild(e.getTarget());
16190         if(item){
16191             this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16192         }
16193     },
16194
16195     onItemClick : function(item, index, e)
16196     {
16197         if(this.fireEvent("beforeclick", this, index, item, e) === false){
16198             return false;
16199         }
16200         if (this.toggleSelect) {
16201             var m = this.isSelected(item) ? 'unselect' : 'select';
16202             //Roo.log(m);
16203             var _t = this;
16204             _t[m](item, true, false);
16205             return true;
16206         }
16207         if(this.multiSelect || this.singleSelect){
16208             if(this.multiSelect && e.shiftKey && this.lastSelection){
16209                 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16210             }else{
16211                 this.select(item, this.multiSelect && e.ctrlKey);
16212                 this.lastSelection = item;
16213             }
16214             
16215             if(!this.tickable){
16216                 e.preventDefault();
16217             }
16218             
16219         }
16220         return true;
16221     },
16222
16223     /**
16224      * Get the number of selected nodes.
16225      * @return {Number}
16226      */
16227     getSelectionCount : function(){
16228         return this.selections.length;
16229     },
16230
16231     /**
16232      * Get the currently selected nodes.
16233      * @return {Array} An array of HTMLElements
16234      */
16235     getSelectedNodes : function(){
16236         return this.selections;
16237     },
16238
16239     /**
16240      * Get the indexes of the selected nodes.
16241      * @return {Array}
16242      */
16243     getSelectedIndexes : function(){
16244         var indexes = [], s = this.selections;
16245         for(var i = 0, len = s.length; i < len; i++){
16246             indexes.push(s[i].nodeIndex);
16247         }
16248         return indexes;
16249     },
16250
16251     /**
16252      * Clear all selections
16253      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16254      */
16255     clearSelections : function(suppressEvent){
16256         if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16257             this.cmp.elements = this.selections;
16258             this.cmp.removeClass(this.selectedClass);
16259             this.selections = [];
16260             if(!suppressEvent){
16261                 this.fireEvent("selectionchange", this, this.selections);
16262             }
16263         }
16264     },
16265
16266     /**
16267      * Returns true if the passed node is selected
16268      * @param {HTMLElement/Number} node The node or node index
16269      * @return {Boolean}
16270      */
16271     isSelected : function(node){
16272         var s = this.selections;
16273         if(s.length < 1){
16274             return false;
16275         }
16276         node = this.getNode(node);
16277         return s.indexOf(node) !== -1;
16278     },
16279
16280     /**
16281      * Selects nodes.
16282      * @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
16283      * @param {Boolean} keepExisting (optional) true to keep existing selections
16284      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16285      */
16286     select : function(nodeInfo, keepExisting, suppressEvent){
16287         if(nodeInfo instanceof Array){
16288             if(!keepExisting){
16289                 this.clearSelections(true);
16290             }
16291             for(var i = 0, len = nodeInfo.length; i < len; i++){
16292                 this.select(nodeInfo[i], true, true);
16293             }
16294             return;
16295         } 
16296         var node = this.getNode(nodeInfo);
16297         if(!node || this.isSelected(node)){
16298             return; // already selected.
16299         }
16300         if(!keepExisting){
16301             this.clearSelections(true);
16302         }
16303         
16304         if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16305             Roo.fly(node).addClass(this.selectedClass);
16306             this.selections.push(node);
16307             if(!suppressEvent){
16308                 this.fireEvent("selectionchange", this, this.selections);
16309             }
16310         }
16311         
16312         
16313     },
16314       /**
16315      * Unselects nodes.
16316      * @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
16317      * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16318      * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16319      */
16320     unselect : function(nodeInfo, keepExisting, suppressEvent)
16321     {
16322         if(nodeInfo instanceof Array){
16323             Roo.each(this.selections, function(s) {
16324                 this.unselect(s, nodeInfo);
16325             }, this);
16326             return;
16327         }
16328         var node = this.getNode(nodeInfo);
16329         if(!node || !this.isSelected(node)){
16330             //Roo.log("not selected");
16331             return; // not selected.
16332         }
16333         // fireevent???
16334         var ns = [];
16335         Roo.each(this.selections, function(s) {
16336             if (s == node ) {
16337                 Roo.fly(node).removeClass(this.selectedClass);
16338
16339                 return;
16340             }
16341             ns.push(s);
16342         },this);
16343         
16344         this.selections= ns;
16345         this.fireEvent("selectionchange", this, this.selections);
16346     },
16347
16348     /**
16349      * Gets a template node.
16350      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16351      * @return {HTMLElement} The node or null if it wasn't found
16352      */
16353     getNode : function(nodeInfo){
16354         if(typeof nodeInfo == "string"){
16355             return document.getElementById(nodeInfo);
16356         }else if(typeof nodeInfo == "number"){
16357             return this.nodes[nodeInfo];
16358         }
16359         return nodeInfo;
16360     },
16361
16362     /**
16363      * Gets a range template nodes.
16364      * @param {Number} startIndex
16365      * @param {Number} endIndex
16366      * @return {Array} An array of nodes
16367      */
16368     getNodes : function(start, end){
16369         var ns = this.nodes;
16370         start = start || 0;
16371         end = typeof end == "undefined" ? ns.length - 1 : end;
16372         var nodes = [];
16373         if(start <= end){
16374             for(var i = start; i <= end; i++){
16375                 nodes.push(ns[i]);
16376             }
16377         } else{
16378             for(var i = start; i >= end; i--){
16379                 nodes.push(ns[i]);
16380             }
16381         }
16382         return nodes;
16383     },
16384
16385     /**
16386      * Finds the index of the passed node
16387      * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16388      * @return {Number} The index of the node or -1
16389      */
16390     indexOf : function(node){
16391         node = this.getNode(node);
16392         if(typeof node.nodeIndex == "number"){
16393             return node.nodeIndex;
16394         }
16395         var ns = this.nodes;
16396         for(var i = 0, len = ns.length; i < len; i++){
16397             if(ns[i] == node){
16398                 return i;
16399             }
16400         }
16401         return -1;
16402     }
16403 });
16404 /*
16405  * - LGPL
16406  *
16407  * based on jquery fullcalendar
16408  * 
16409  */
16410
16411 Roo.bootstrap = Roo.bootstrap || {};
16412 /**
16413  * @class Roo.bootstrap.Calendar
16414  * @extends Roo.bootstrap.Component
16415  * Bootstrap Calendar class
16416  * @cfg {Boolean} loadMask (true|false) default false
16417  * @cfg {Object} header generate the user specific header of the calendar, default false
16418
16419  * @constructor
16420  * Create a new Container
16421  * @param {Object} config The config object
16422  */
16423
16424
16425
16426 Roo.bootstrap.Calendar = function(config){
16427     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16428      this.addEvents({
16429         /**
16430              * @event select
16431              * Fires when a date is selected
16432              * @param {DatePicker} this
16433              * @param {Date} date The selected date
16434              */
16435         'select': true,
16436         /**
16437              * @event monthchange
16438              * Fires when the displayed month changes 
16439              * @param {DatePicker} this
16440              * @param {Date} date The selected month
16441              */
16442         'monthchange': true,
16443         /**
16444              * @event evententer
16445              * Fires when mouse over an event
16446              * @param {Calendar} this
16447              * @param {event} Event
16448              */
16449         'evententer': true,
16450         /**
16451              * @event eventleave
16452              * Fires when the mouse leaves an
16453              * @param {Calendar} this
16454              * @param {event}
16455              */
16456         'eventleave': true,
16457         /**
16458              * @event eventclick
16459              * Fires when the mouse click an
16460              * @param {Calendar} this
16461              * @param {event}
16462              */
16463         'eventclick': true
16464         
16465     });
16466
16467 };
16468
16469 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
16470     
16471      /**
16472      * @cfg {Number} startDay
16473      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16474      */
16475     startDay : 0,
16476     
16477     loadMask : false,
16478     
16479     header : false,
16480       
16481     getAutoCreate : function(){
16482         
16483         
16484         var fc_button = function(name, corner, style, content ) {
16485             return Roo.apply({},{
16486                 tag : 'span',
16487                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
16488                          (corner.length ?
16489                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16490                             ''
16491                         ),
16492                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16493                 unselectable: 'on'
16494             });
16495         };
16496         
16497         var header = {};
16498         
16499         if(!this.header){
16500             header = {
16501                 tag : 'table',
16502                 cls : 'fc-header',
16503                 style : 'width:100%',
16504                 cn : [
16505                     {
16506                         tag: 'tr',
16507                         cn : [
16508                             {
16509                                 tag : 'td',
16510                                 cls : 'fc-header-left',
16511                                 cn : [
16512                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
16513                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
16514                                     { tag: 'span', cls: 'fc-header-space' },
16515                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
16516
16517
16518                                 ]
16519                             },
16520
16521                             {
16522                                 tag : 'td',
16523                                 cls : 'fc-header-center',
16524                                 cn : [
16525                                     {
16526                                         tag: 'span',
16527                                         cls: 'fc-header-title',
16528                                         cn : {
16529                                             tag: 'H2',
16530                                             html : 'month / year'
16531                                         }
16532                                     }
16533
16534                                 ]
16535                             },
16536                             {
16537                                 tag : 'td',
16538                                 cls : 'fc-header-right',
16539                                 cn : [
16540                               /*      fc_button('month', 'left', '', 'month' ),
16541                                     fc_button('week', '', '', 'week' ),
16542                                     fc_button('day', 'right', '', 'day' )
16543                                 */    
16544
16545                                 ]
16546                             }
16547
16548                         ]
16549                     }
16550                 ]
16551             };
16552         }
16553         
16554         header = this.header;
16555         
16556        
16557         var cal_heads = function() {
16558             var ret = [];
16559             // fixme - handle this.
16560             
16561             for (var i =0; i < Date.dayNames.length; i++) {
16562                 var d = Date.dayNames[i];
16563                 ret.push({
16564                     tag: 'th',
16565                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16566                     html : d.substring(0,3)
16567                 });
16568                 
16569             }
16570             ret[0].cls += ' fc-first';
16571             ret[6].cls += ' fc-last';
16572             return ret;
16573         };
16574         var cal_cell = function(n) {
16575             return  {
16576                 tag: 'td',
16577                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16578                 cn : [
16579                     {
16580                         cn : [
16581                             {
16582                                 cls: 'fc-day-number',
16583                                 html: 'D'
16584                             },
16585                             {
16586                                 cls: 'fc-day-content',
16587                              
16588                                 cn : [
16589                                      {
16590                                         style: 'position: relative;' // height: 17px;
16591                                     }
16592                                 ]
16593                             }
16594                             
16595                             
16596                         ]
16597                     }
16598                 ]
16599                 
16600             }
16601         };
16602         var cal_rows = function() {
16603             
16604             var ret = [];
16605             for (var r = 0; r < 6; r++) {
16606                 var row= {
16607                     tag : 'tr',
16608                     cls : 'fc-week',
16609                     cn : []
16610                 };
16611                 
16612                 for (var i =0; i < Date.dayNames.length; i++) {
16613                     var d = Date.dayNames[i];
16614                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16615
16616                 }
16617                 row.cn[0].cls+=' fc-first';
16618                 row.cn[0].cn[0].style = 'min-height:90px';
16619                 row.cn[6].cls+=' fc-last';
16620                 ret.push(row);
16621                 
16622             }
16623             ret[0].cls += ' fc-first';
16624             ret[4].cls += ' fc-prev-last';
16625             ret[5].cls += ' fc-last';
16626             return ret;
16627             
16628         };
16629         
16630         var cal_table = {
16631             tag: 'table',
16632             cls: 'fc-border-separate',
16633             style : 'width:100%',
16634             cellspacing  : 0,
16635             cn : [
16636                 { 
16637                     tag: 'thead',
16638                     cn : [
16639                         { 
16640                             tag: 'tr',
16641                             cls : 'fc-first fc-last',
16642                             cn : cal_heads()
16643                         }
16644                     ]
16645                 },
16646                 { 
16647                     tag: 'tbody',
16648                     cn : cal_rows()
16649                 }
16650                   
16651             ]
16652         };
16653          
16654          var cfg = {
16655             cls : 'fc fc-ltr',
16656             cn : [
16657                 header,
16658                 {
16659                     cls : 'fc-content',
16660                     style : "position: relative;",
16661                     cn : [
16662                         {
16663                             cls : 'fc-view fc-view-month fc-grid',
16664                             style : 'position: relative',
16665                             unselectable : 'on',
16666                             cn : [
16667                                 {
16668                                     cls : 'fc-event-container',
16669                                     style : 'position:absolute;z-index:8;top:0;left:0;'
16670                                 },
16671                                 cal_table
16672                             ]
16673                         }
16674                     ]
16675     
16676                 }
16677            ] 
16678             
16679         };
16680         
16681          
16682         
16683         return cfg;
16684     },
16685     
16686     
16687     initEvents : function()
16688     {
16689         if(!this.store){
16690             throw "can not find store for calendar";
16691         }
16692         
16693         var mark = {
16694             tag: "div",
16695             cls:"x-dlg-mask",
16696             style: "text-align:center",
16697             cn: [
16698                 {
16699                     tag: "div",
16700                     style: "background-color:white;width:50%;margin:250 auto",
16701                     cn: [
16702                         {
16703                             tag: "img",
16704                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
16705                         },
16706                         {
16707                             tag: "span",
16708                             html: "Loading"
16709                         }
16710                         
16711                     ]
16712                 }
16713             ]
16714         };
16715         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16716         
16717         var size = this.el.select('.fc-content', true).first().getSize();
16718         this.maskEl.setSize(size.width, size.height);
16719         this.maskEl.enableDisplayMode("block");
16720         if(!this.loadMask){
16721             this.maskEl.hide();
16722         }
16723         
16724         this.store = Roo.factory(this.store, Roo.data);
16725         this.store.on('load', this.onLoad, this);
16726         this.store.on('beforeload', this.onBeforeLoad, this);
16727         
16728         this.resize();
16729         
16730         this.cells = this.el.select('.fc-day',true);
16731         //Roo.log(this.cells);
16732         this.textNodes = this.el.query('.fc-day-number');
16733         this.cells.addClassOnOver('fc-state-hover');
16734         
16735         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
16736         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
16737         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
16738         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
16739         
16740         this.on('monthchange', this.onMonthChange, this);
16741         
16742         this.update(new Date().clearTime());
16743     },
16744     
16745     resize : function() {
16746         var sz  = this.el.getSize();
16747         
16748         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
16749         this.el.select('.fc-day-content div',true).setHeight(34);
16750     },
16751     
16752     
16753     // private
16754     showPrevMonth : function(e){
16755         this.update(this.activeDate.add("mo", -1));
16756     },
16757     showToday : function(e){
16758         this.update(new Date().clearTime());
16759     },
16760     // private
16761     showNextMonth : function(e){
16762         this.update(this.activeDate.add("mo", 1));
16763     },
16764
16765     // private
16766     showPrevYear : function(){
16767         this.update(this.activeDate.add("y", -1));
16768     },
16769
16770     // private
16771     showNextYear : function(){
16772         this.update(this.activeDate.add("y", 1));
16773     },
16774
16775     
16776    // private
16777     update : function(date)
16778     {
16779         var vd = this.activeDate;
16780         this.activeDate = date;
16781 //        if(vd && this.el){
16782 //            var t = date.getTime();
16783 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
16784 //                Roo.log('using add remove');
16785 //                
16786 //                this.fireEvent('monthchange', this, date);
16787 //                
16788 //                this.cells.removeClass("fc-state-highlight");
16789 //                this.cells.each(function(c){
16790 //                   if(c.dateValue == t){
16791 //                       c.addClass("fc-state-highlight");
16792 //                       setTimeout(function(){
16793 //                            try{c.dom.firstChild.focus();}catch(e){}
16794 //                       }, 50);
16795 //                       return false;
16796 //                   }
16797 //                   return true;
16798 //                });
16799 //                return;
16800 //            }
16801 //        }
16802         
16803         var days = date.getDaysInMonth();
16804         
16805         var firstOfMonth = date.getFirstDateOfMonth();
16806         var startingPos = firstOfMonth.getDay()-this.startDay;
16807         
16808         if(startingPos < this.startDay){
16809             startingPos += 7;
16810         }
16811         
16812         var pm = date.add(Date.MONTH, -1);
16813         var prevStart = pm.getDaysInMonth()-startingPos;
16814 //        
16815         this.cells = this.el.select('.fc-day',true);
16816         this.textNodes = this.el.query('.fc-day-number');
16817         this.cells.addClassOnOver('fc-state-hover');
16818         
16819         var cells = this.cells.elements;
16820         var textEls = this.textNodes;
16821         
16822         Roo.each(cells, function(cell){
16823             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
16824         });
16825         
16826         days += startingPos;
16827
16828         // convert everything to numbers so it's fast
16829         var day = 86400000;
16830         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
16831         //Roo.log(d);
16832         //Roo.log(pm);
16833         //Roo.log(prevStart);
16834         
16835         var today = new Date().clearTime().getTime();
16836         var sel = date.clearTime().getTime();
16837         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
16838         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
16839         var ddMatch = this.disabledDatesRE;
16840         var ddText = this.disabledDatesText;
16841         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
16842         var ddaysText = this.disabledDaysText;
16843         var format = this.format;
16844         
16845         var setCellClass = function(cal, cell){
16846             cell.row = 0;
16847             cell.events = [];
16848             cell.more = [];
16849             //Roo.log('set Cell Class');
16850             cell.title = "";
16851             var t = d.getTime();
16852             
16853             //Roo.log(d);
16854             
16855             cell.dateValue = t;
16856             if(t == today){
16857                 cell.className += " fc-today";
16858                 cell.className += " fc-state-highlight";
16859                 cell.title = cal.todayText;
16860             }
16861             if(t == sel){
16862                 // disable highlight in other month..
16863                 //cell.className += " fc-state-highlight";
16864                 
16865             }
16866             // disabling
16867             if(t < min) {
16868                 cell.className = " fc-state-disabled";
16869                 cell.title = cal.minText;
16870                 return;
16871             }
16872             if(t > max) {
16873                 cell.className = " fc-state-disabled";
16874                 cell.title = cal.maxText;
16875                 return;
16876             }
16877             if(ddays){
16878                 if(ddays.indexOf(d.getDay()) != -1){
16879                     cell.title = ddaysText;
16880                     cell.className = " fc-state-disabled";
16881                 }
16882             }
16883             if(ddMatch && format){
16884                 var fvalue = d.dateFormat(format);
16885                 if(ddMatch.test(fvalue)){
16886                     cell.title = ddText.replace("%0", fvalue);
16887                     cell.className = " fc-state-disabled";
16888                 }
16889             }
16890             
16891             if (!cell.initialClassName) {
16892                 cell.initialClassName = cell.dom.className;
16893             }
16894             
16895             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
16896         };
16897
16898         var i = 0;
16899         
16900         for(; i < startingPos; i++) {
16901             textEls[i].innerHTML = (++prevStart);
16902             d.setDate(d.getDate()+1);
16903             
16904             cells[i].className = "fc-past fc-other-month";
16905             setCellClass(this, cells[i]);
16906         }
16907         
16908         var intDay = 0;
16909         
16910         for(; i < days; i++){
16911             intDay = i - startingPos + 1;
16912             textEls[i].innerHTML = (intDay);
16913             d.setDate(d.getDate()+1);
16914             
16915             cells[i].className = ''; // "x-date-active";
16916             setCellClass(this, cells[i]);
16917         }
16918         var extraDays = 0;
16919         
16920         for(; i < 42; i++) {
16921             textEls[i].innerHTML = (++extraDays);
16922             d.setDate(d.getDate()+1);
16923             
16924             cells[i].className = "fc-future fc-other-month";
16925             setCellClass(this, cells[i]);
16926         }
16927         
16928         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
16929         
16930         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
16931         
16932         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
16933         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
16934         
16935         if(totalRows != 6){
16936             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
16937             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
16938         }
16939         
16940         this.fireEvent('monthchange', this, date);
16941         
16942         
16943         /*
16944         if(!this.internalRender){
16945             var main = this.el.dom.firstChild;
16946             var w = main.offsetWidth;
16947             this.el.setWidth(w + this.el.getBorderWidth("lr"));
16948             Roo.fly(main).setWidth(w);
16949             this.internalRender = true;
16950             // opera does not respect the auto grow header center column
16951             // then, after it gets a width opera refuses to recalculate
16952             // without a second pass
16953             if(Roo.isOpera && !this.secondPass){
16954                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
16955                 this.secondPass = true;
16956                 this.update.defer(10, this, [date]);
16957             }
16958         }
16959         */
16960         
16961     },
16962     
16963     findCell : function(dt) {
16964         dt = dt.clearTime().getTime();
16965         var ret = false;
16966         this.cells.each(function(c){
16967             //Roo.log("check " +c.dateValue + '?=' + dt);
16968             if(c.dateValue == dt){
16969                 ret = c;
16970                 return false;
16971             }
16972             return true;
16973         });
16974         
16975         return ret;
16976     },
16977     
16978     findCells : function(ev) {
16979         var s = ev.start.clone().clearTime().getTime();
16980        // Roo.log(s);
16981         var e= ev.end.clone().clearTime().getTime();
16982        // Roo.log(e);
16983         var ret = [];
16984         this.cells.each(function(c){
16985              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
16986             
16987             if(c.dateValue > e){
16988                 return ;
16989             }
16990             if(c.dateValue < s){
16991                 return ;
16992             }
16993             ret.push(c);
16994         });
16995         
16996         return ret;    
16997     },
16998     
16999 //    findBestRow: function(cells)
17000 //    {
17001 //        var ret = 0;
17002 //        
17003 //        for (var i =0 ; i < cells.length;i++) {
17004 //            ret  = Math.max(cells[i].rows || 0,ret);
17005 //        }
17006 //        return ret;
17007 //        
17008 //    },
17009     
17010     
17011     addItem : function(ev)
17012     {
17013         // look for vertical location slot in
17014         var cells = this.findCells(ev);
17015         
17016 //        ev.row = this.findBestRow(cells);
17017         
17018         // work out the location.
17019         
17020         var crow = false;
17021         var rows = [];
17022         for(var i =0; i < cells.length; i++) {
17023             
17024             cells[i].row = cells[0].row;
17025             
17026             if(i == 0){
17027                 cells[i].row = cells[i].row + 1;
17028             }
17029             
17030             if (!crow) {
17031                 crow = {
17032                     start : cells[i],
17033                     end :  cells[i]
17034                 };
17035                 continue;
17036             }
17037             if (crow.start.getY() == cells[i].getY()) {
17038                 // on same row.
17039                 crow.end = cells[i];
17040                 continue;
17041             }
17042             // different row.
17043             rows.push(crow);
17044             crow = {
17045                 start: cells[i],
17046                 end : cells[i]
17047             };
17048             
17049         }
17050         
17051         rows.push(crow);
17052         ev.els = [];
17053         ev.rows = rows;
17054         ev.cells = cells;
17055         
17056         cells[0].events.push(ev);
17057         
17058         this.calevents.push(ev);
17059     },
17060     
17061     clearEvents: function() {
17062         
17063         if(!this.calevents){
17064             return;
17065         }
17066         
17067         Roo.each(this.cells.elements, function(c){
17068             c.row = 0;
17069             c.events = [];
17070             c.more = [];
17071         });
17072         
17073         Roo.each(this.calevents, function(e) {
17074             Roo.each(e.els, function(el) {
17075                 el.un('mouseenter' ,this.onEventEnter, this);
17076                 el.un('mouseleave' ,this.onEventLeave, this);
17077                 el.remove();
17078             },this);
17079         },this);
17080         
17081         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17082             e.remove();
17083         });
17084         
17085     },
17086     
17087     renderEvents: function()
17088     {   
17089         var _this = this;
17090         
17091         this.cells.each(function(c) {
17092             
17093             if(c.row < 5){
17094                 return;
17095             }
17096             
17097             var ev = c.events;
17098             
17099             var r = 4;
17100             if(c.row != c.events.length){
17101                 r = 4 - (4 - (c.row - c.events.length));
17102             }
17103             
17104             c.events = ev.slice(0, r);
17105             c.more = ev.slice(r);
17106             
17107             if(c.more.length && c.more.length == 1){
17108                 c.events.push(c.more.pop());
17109             }
17110             
17111             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17112             
17113         });
17114             
17115         this.cells.each(function(c) {
17116             
17117             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17118             
17119             
17120             for (var e = 0; e < c.events.length; e++){
17121                 var ev = c.events[e];
17122                 var rows = ev.rows;
17123                 
17124                 for(var i = 0; i < rows.length; i++) {
17125                 
17126                     // how many rows should it span..
17127
17128                     var  cfg = {
17129                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17130                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17131
17132                         unselectable : "on",
17133                         cn : [
17134                             {
17135                                 cls: 'fc-event-inner',
17136                                 cn : [
17137     //                                {
17138     //                                  tag:'span',
17139     //                                  cls: 'fc-event-time',
17140     //                                  html : cells.length > 1 ? '' : ev.time
17141     //                                },
17142                                     {
17143                                       tag:'span',
17144                                       cls: 'fc-event-title',
17145                                       html : String.format('{0}', ev.title)
17146                                     }
17147
17148
17149                                 ]
17150                             },
17151                             {
17152                                 cls: 'ui-resizable-handle ui-resizable-e',
17153                                 html : '&nbsp;&nbsp;&nbsp'
17154                             }
17155
17156                         ]
17157                     };
17158
17159                     if (i == 0) {
17160                         cfg.cls += ' fc-event-start';
17161                     }
17162                     if ((i+1) == rows.length) {
17163                         cfg.cls += ' fc-event-end';
17164                     }
17165
17166                     var ctr = _this.el.select('.fc-event-container',true).first();
17167                     var cg = ctr.createChild(cfg);
17168
17169                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17170                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17171
17172                     var r = (c.more.length) ? 1 : 0;
17173                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
17174                     cg.setWidth(ebox.right - sbox.x -2);
17175
17176                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17177                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17178                     cg.on('click', _this.onEventClick, _this, ev);
17179
17180                     ev.els.push(cg);
17181                     
17182                 }
17183                 
17184             }
17185             
17186             
17187             if(c.more.length){
17188                 var  cfg = {
17189                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17190                     style : 'position: absolute',
17191                     unselectable : "on",
17192                     cn : [
17193                         {
17194                             cls: 'fc-event-inner',
17195                             cn : [
17196                                 {
17197                                   tag:'span',
17198                                   cls: 'fc-event-title',
17199                                   html : 'More'
17200                                 }
17201
17202
17203                             ]
17204                         },
17205                         {
17206                             cls: 'ui-resizable-handle ui-resizable-e',
17207                             html : '&nbsp;&nbsp;&nbsp'
17208                         }
17209
17210                     ]
17211                 };
17212
17213                 var ctr = _this.el.select('.fc-event-container',true).first();
17214                 var cg = ctr.createChild(cfg);
17215
17216                 var sbox = c.select('.fc-day-content',true).first().getBox();
17217                 var ebox = c.select('.fc-day-content',true).first().getBox();
17218                 //Roo.log(cg);
17219                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
17220                 cg.setWidth(ebox.right - sbox.x -2);
17221
17222                 cg.on('click', _this.onMoreEventClick, _this, c.more);
17223                 
17224             }
17225             
17226         });
17227         
17228         
17229         
17230     },
17231     
17232     onEventEnter: function (e, el,event,d) {
17233         this.fireEvent('evententer', this, el, event);
17234     },
17235     
17236     onEventLeave: function (e, el,event,d) {
17237         this.fireEvent('eventleave', this, el, event);
17238     },
17239     
17240     onEventClick: function (e, el,event,d) {
17241         this.fireEvent('eventclick', this, el, event);
17242     },
17243     
17244     onMonthChange: function () {
17245         this.store.load();
17246     },
17247     
17248     onMoreEventClick: function(e, el, more)
17249     {
17250         var _this = this;
17251         
17252         this.calpopover.placement = 'right';
17253         this.calpopover.setTitle('More');
17254         
17255         this.calpopover.setContent('');
17256         
17257         var ctr = this.calpopover.el.select('.popover-content', true).first();
17258         
17259         Roo.each(more, function(m){
17260             var cfg = {
17261                 cls : 'fc-event-hori fc-event-draggable',
17262                 html : m.title
17263             };
17264             var cg = ctr.createChild(cfg);
17265             
17266             cg.on('click', _this.onEventClick, _this, m);
17267         });
17268         
17269         this.calpopover.show(el);
17270         
17271         
17272     },
17273     
17274     onLoad: function () 
17275     {   
17276         this.calevents = [];
17277         var cal = this;
17278         
17279         if(this.store.getCount() > 0){
17280             this.store.data.each(function(d){
17281                cal.addItem({
17282                     id : d.data.id,
17283                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17284                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17285                     time : d.data.start_time,
17286                     title : d.data.title,
17287                     description : d.data.description,
17288                     venue : d.data.venue
17289                 });
17290             });
17291         }
17292         
17293         this.renderEvents();
17294         
17295         if(this.calevents.length && this.loadMask){
17296             this.maskEl.hide();
17297         }
17298     },
17299     
17300     onBeforeLoad: function()
17301     {
17302         this.clearEvents();
17303         if(this.loadMask){
17304             this.maskEl.show();
17305         }
17306     }
17307 });
17308
17309  
17310  /*
17311  * - LGPL
17312  *
17313  * element
17314  * 
17315  */
17316
17317 /**
17318  * @class Roo.bootstrap.Popover
17319  * @extends Roo.bootstrap.Component
17320  * Bootstrap Popover class
17321  * @cfg {String} html contents of the popover   (or false to use children..)
17322  * @cfg {String} title of popover (or false to hide)
17323  * @cfg {String} placement how it is placed
17324  * @cfg {String} trigger click || hover (or false to trigger manually)
17325  * @cfg {String} over what (parent or false to trigger manually.)
17326  * @cfg {Number} delay - delay before showing
17327  
17328  * @constructor
17329  * Create a new Popover
17330  * @param {Object} config The config object
17331  */
17332
17333 Roo.bootstrap.Popover = function(config){
17334     Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17335     
17336     this.addEvents({
17337         // raw events
17338          /**
17339          * @event show
17340          * After the popover show
17341          * 
17342          * @param {Roo.bootstrap.Popover} this
17343          */
17344         "show" : true,
17345         /**
17346          * @event hide
17347          * After the popover hide
17348          * 
17349          * @param {Roo.bootstrap.Popover} this
17350          */
17351         "hide" : true
17352     });
17353 };
17354
17355 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component,  {
17356     
17357     title: 'Fill in a title',
17358     html: false,
17359     
17360     placement : 'right',
17361     trigger : 'hover', // hover
17362     
17363     delay : 0,
17364     
17365     over: 'parent',
17366     
17367     can_build_overlaid : false,
17368     
17369     getChildContainer : function()
17370     {
17371         return this.el.select('.popover-content',true).first();
17372     },
17373     
17374     getAutoCreate : function(){
17375          
17376         var cfg = {
17377            cls : 'popover roo-dynamic',
17378            style: 'display:block',
17379            cn : [
17380                 {
17381                     cls : 'arrow'
17382                 },
17383                 {
17384                     cls : 'popover-inner',
17385                     cn : [
17386                         {
17387                             tag: 'h3',
17388                             cls: 'popover-title',
17389                             html : this.title
17390                         },
17391                         {
17392                             cls : 'popover-content',
17393                             html : this.html
17394                         }
17395                     ]
17396                     
17397                 }
17398            ]
17399         };
17400         
17401         return cfg;
17402     },
17403     setTitle: function(str)
17404     {
17405         this.title = str;
17406         this.el.select('.popover-title',true).first().dom.innerHTML = str;
17407     },
17408     setContent: function(str)
17409     {
17410         this.html = str;
17411         this.el.select('.popover-content',true).first().dom.innerHTML = str;
17412     },
17413     // as it get's added to the bottom of the page.
17414     onRender : function(ct, position)
17415     {
17416         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17417         if(!this.el){
17418             var cfg = Roo.apply({},  this.getAutoCreate());
17419             cfg.id = Roo.id();
17420             
17421             if (this.cls) {
17422                 cfg.cls += ' ' + this.cls;
17423             }
17424             if (this.style) {
17425                 cfg.style = this.style;
17426             }
17427             //Roo.log("adding to ");
17428             this.el = Roo.get(document.body).createChild(cfg, position);
17429 //            Roo.log(this.el);
17430         }
17431         this.initEvents();
17432     },
17433     
17434     initEvents : function()
17435     {
17436         this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17437         this.el.enableDisplayMode('block');
17438         this.el.hide();
17439         if (this.over === false) {
17440             return; 
17441         }
17442         if (this.triggers === false) {
17443             return;
17444         }
17445         var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17446         var triggers = this.trigger ? this.trigger.split(' ') : [];
17447         Roo.each(triggers, function(trigger) {
17448         
17449             if (trigger == 'click') {
17450                 on_el.on('click', this.toggle, this);
17451             } else if (trigger != 'manual') {
17452                 var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin';
17453                 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17454       
17455                 on_el.on(eventIn  ,this.enter, this);
17456                 on_el.on(eventOut, this.leave, this);
17457             }
17458         }, this);
17459         
17460     },
17461     
17462     
17463     // private
17464     timeout : null,
17465     hoverState : null,
17466     
17467     toggle : function () {
17468         this.hoverState == 'in' ? this.leave() : this.enter();
17469     },
17470     
17471     enter : function () {
17472         
17473         clearTimeout(this.timeout);
17474     
17475         this.hoverState = 'in';
17476     
17477         if (!this.delay || !this.delay.show) {
17478             this.show();
17479             return;
17480         }
17481         var _t = this;
17482         this.timeout = setTimeout(function () {
17483             if (_t.hoverState == 'in') {
17484                 _t.show();
17485             }
17486         }, this.delay.show)
17487     },
17488     
17489     leave : function() {
17490         clearTimeout(this.timeout);
17491     
17492         this.hoverState = 'out';
17493     
17494         if (!this.delay || !this.delay.hide) {
17495             this.hide();
17496             return;
17497         }
17498         var _t = this;
17499         this.timeout = setTimeout(function () {
17500             if (_t.hoverState == 'out') {
17501                 _t.hide();
17502             }
17503         }, this.delay.hide)
17504     },
17505     
17506     show : function (on_el)
17507     {
17508         if (!on_el) {
17509             on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17510         }
17511         
17512         // set content.
17513         this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17514         if (this.html !== false) {
17515             this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17516         }
17517         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
17518         if (!this.title.length) {
17519             this.el.select('.popover-title',true).hide();
17520         }
17521         
17522         var placement = typeof this.placement == 'function' ?
17523             this.placement.call(this, this.el, on_el) :
17524             this.placement;
17525             
17526         var autoToken = /\s?auto?\s?/i;
17527         var autoPlace = autoToken.test(placement);
17528         if (autoPlace) {
17529             placement = placement.replace(autoToken, '') || 'top';
17530         }
17531         
17532         //this.el.detach()
17533         //this.el.setXY([0,0]);
17534         this.el.show();
17535         this.el.dom.style.display='block';
17536         this.el.addClass(placement);
17537         
17538         //this.el.appendTo(on_el);
17539         
17540         var p = this.getPosition();
17541         var box = this.el.getBox();
17542         
17543         if (autoPlace) {
17544             // fixme..
17545         }
17546         var align = Roo.bootstrap.Popover.alignment[placement];
17547         
17548 //        Roo.log(align);
17549         this.el.alignTo(on_el, align[0],align[1]);
17550         //var arrow = this.el.select('.arrow',true).first();
17551         //arrow.set(align[2], 
17552         
17553         this.el.addClass('in');
17554         
17555         
17556         if (this.el.hasClass('fade')) {
17557             // fade it?
17558         }
17559         
17560         this.hoverState = 'in';
17561         
17562         this.fireEvent('show', this);
17563         
17564     },
17565     hide : function()
17566     {
17567         this.el.setXY([0,0]);
17568         this.el.removeClass('in');
17569         this.el.hide();
17570         this.hoverState = null;
17571         
17572         this.fireEvent('hide', this);
17573     }
17574     
17575 });
17576
17577 Roo.bootstrap.Popover.alignment = {
17578     'left' : ['r-l', [-10,0], 'right'],
17579     'right' : ['l-r', [10,0], 'left'],
17580     'bottom' : ['t-b', [0,10], 'top'],
17581     'top' : [ 'b-t', [0,-10], 'bottom']
17582 };
17583
17584  /*
17585  * - LGPL
17586  *
17587  * Progress
17588  * 
17589  */
17590
17591 /**
17592  * @class Roo.bootstrap.Progress
17593  * @extends Roo.bootstrap.Component
17594  * Bootstrap Progress class
17595  * @cfg {Boolean} striped striped of the progress bar
17596  * @cfg {Boolean} active animated of the progress bar
17597  * 
17598  * 
17599  * @constructor
17600  * Create a new Progress
17601  * @param {Object} config The config object
17602  */
17603
17604 Roo.bootstrap.Progress = function(config){
17605     Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17606 };
17607
17608 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component,  {
17609     
17610     striped : false,
17611     active: false,
17612     
17613     getAutoCreate : function(){
17614         var cfg = {
17615             tag: 'div',
17616             cls: 'progress'
17617         };
17618         
17619         
17620         if(this.striped){
17621             cfg.cls += ' progress-striped';
17622         }
17623       
17624         if(this.active){
17625             cfg.cls += ' active';
17626         }
17627         
17628         
17629         return cfg;
17630     }
17631    
17632 });
17633
17634  
17635
17636  /*
17637  * - LGPL
17638  *
17639  * ProgressBar
17640  * 
17641  */
17642
17643 /**
17644  * @class Roo.bootstrap.ProgressBar
17645  * @extends Roo.bootstrap.Component
17646  * Bootstrap ProgressBar class
17647  * @cfg {Number} aria_valuenow aria-value now
17648  * @cfg {Number} aria_valuemin aria-value min
17649  * @cfg {Number} aria_valuemax aria-value max
17650  * @cfg {String} label label for the progress bar
17651  * @cfg {String} panel (success | info | warning | danger )
17652  * @cfg {String} role role of the progress bar
17653  * @cfg {String} sr_only text
17654  * 
17655  * 
17656  * @constructor
17657  * Create a new ProgressBar
17658  * @param {Object} config The config object
17659  */
17660
17661 Roo.bootstrap.ProgressBar = function(config){
17662     Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17663 };
17664
17665 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component,  {
17666     
17667     aria_valuenow : 0,
17668     aria_valuemin : 0,
17669     aria_valuemax : 100,
17670     label : false,
17671     panel : false,
17672     role : false,
17673     sr_only: false,
17674     
17675     getAutoCreate : function()
17676     {
17677         
17678         var cfg = {
17679             tag: 'div',
17680             cls: 'progress-bar',
17681             style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17682         };
17683         
17684         if(this.sr_only){
17685             cfg.cn = {
17686                 tag: 'span',
17687                 cls: 'sr-only',
17688                 html: this.sr_only
17689             }
17690         }
17691         
17692         if(this.role){
17693             cfg.role = this.role;
17694         }
17695         
17696         if(this.aria_valuenow){
17697             cfg['aria-valuenow'] = this.aria_valuenow;
17698         }
17699         
17700         if(this.aria_valuemin){
17701             cfg['aria-valuemin'] = this.aria_valuemin;
17702         }
17703         
17704         if(this.aria_valuemax){
17705             cfg['aria-valuemax'] = this.aria_valuemax;
17706         }
17707         
17708         if(this.label && !this.sr_only){
17709             cfg.html = this.label;
17710         }
17711         
17712         if(this.panel){
17713             cfg.cls += ' progress-bar-' + this.panel;
17714         }
17715         
17716         return cfg;
17717     },
17718     
17719     update : function(aria_valuenow)
17720     {
17721         this.aria_valuenow = aria_valuenow;
17722         
17723         this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
17724     }
17725    
17726 });
17727
17728  
17729
17730  /*
17731  * - LGPL
17732  *
17733  * column
17734  * 
17735  */
17736
17737 /**
17738  * @class Roo.bootstrap.TabGroup
17739  * @extends Roo.bootstrap.Column
17740  * Bootstrap Column class
17741  * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
17742  * @cfg {Boolean} carousel true to make the group behave like a carousel
17743  * @cfg {Boolean} bullets show bullets for the panels
17744  * @cfg {Boolean} autoslide (true|false) auto slide .. default false
17745  * @cfg {Number} timer auto slide timer .. default 0 millisecond
17746  * @cfg {Boolean} showarrow (true|false) show arrow default true
17747  * 
17748  * @constructor
17749  * Create a new TabGroup
17750  * @param {Object} config The config object
17751  */
17752
17753 Roo.bootstrap.TabGroup = function(config){
17754     Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
17755     if (!this.navId) {
17756         this.navId = Roo.id();
17757     }
17758     this.tabs = [];
17759     Roo.bootstrap.TabGroup.register(this);
17760     
17761 };
17762
17763 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column,  {
17764     
17765     carousel : false,
17766     transition : false,
17767     bullets : 0,
17768     timer : 0,
17769     autoslide : false,
17770     slideFn : false,
17771     slideOnTouch : false,
17772     showarrow : true,
17773     
17774     getAutoCreate : function()
17775     {
17776         var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
17777         
17778         cfg.cls += ' tab-content';
17779         
17780         if (this.carousel) {
17781             cfg.cls += ' carousel slide';
17782             
17783             cfg.cn = [{
17784                cls : 'carousel-inner',
17785                cn : []
17786             }];
17787         
17788             if(this.bullets  && !Roo.isTouch){
17789                 
17790                 var bullets = {
17791                     cls : 'carousel-bullets',
17792                     cn : []
17793                 };
17794                
17795                 if(this.bullets_cls){
17796                     bullets.cls = bullets.cls + ' ' + this.bullets_cls;
17797                 }
17798                 
17799                 bullets.cn.push({
17800                     cls : 'clear'
17801                 });
17802                 
17803                 cfg.cn[0].cn.push(bullets);
17804             }
17805             
17806             if(this.showarrow){
17807                 cfg.cn[0].cn.push({
17808                     tag : 'div',
17809                     class : 'carousel-arrow',
17810                     cn : [
17811                         {
17812                             tag : 'div',
17813                             class : 'carousel-prev',
17814                             cn : [
17815                                 {
17816                                     tag : 'i',
17817                                     class : 'fa fa-chevron-left'
17818                                 }
17819                             ]
17820                         },
17821                         {
17822                             tag : 'div',
17823                             class : 'carousel-next',
17824                             cn : [
17825                                 {
17826                                     tag : 'i',
17827                                     class : 'fa fa-chevron-right'
17828                                 }
17829                             ]
17830                         }
17831                     ]
17832                 });
17833             }
17834             
17835         }
17836         
17837         return cfg;
17838     },
17839     
17840     initEvents:  function()
17841     {
17842 //        if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
17843 //            this.el.on("touchstart", this.onTouchStart, this);
17844 //        }
17845         
17846         if(this.autoslide){
17847             var _this = this;
17848             
17849             this.slideFn = window.setInterval(function() {
17850                 _this.showPanelNext();
17851             }, this.timer);
17852         }
17853         
17854         if(this.showarrow){
17855             this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
17856             this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
17857         }
17858         
17859         
17860     },
17861     
17862 //    onTouchStart : function(e, el, o)
17863 //    {
17864 //        if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
17865 //            return;
17866 //        }
17867 //        
17868 //        this.showPanelNext();
17869 //    },
17870     
17871     
17872     getChildContainer : function()
17873     {
17874         return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
17875     },
17876     
17877     /**
17878     * register a Navigation item
17879     * @param {Roo.bootstrap.NavItem} the navitem to add
17880     */
17881     register : function(item)
17882     {
17883         this.tabs.push( item);
17884         item.navId = this.navId; // not really needed..
17885         this.addBullet();
17886     
17887     },
17888     
17889     getActivePanel : function()
17890     {
17891         var r = false;
17892         Roo.each(this.tabs, function(t) {
17893             if (t.active) {
17894                 r = t;
17895                 return false;
17896             }
17897             return null;
17898         });
17899         return r;
17900         
17901     },
17902     getPanelByName : function(n)
17903     {
17904         var r = false;
17905         Roo.each(this.tabs, function(t) {
17906             if (t.tabId == n) {
17907                 r = t;
17908                 return false;
17909             }
17910             return null;
17911         });
17912         return r;
17913     },
17914     indexOfPanel : function(p)
17915     {
17916         var r = false;
17917         Roo.each(this.tabs, function(t,i) {
17918             if (t.tabId == p.tabId) {
17919                 r = i;
17920                 return false;
17921             }
17922             return null;
17923         });
17924         return r;
17925     },
17926     /**
17927      * show a specific panel
17928      * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
17929      * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
17930      */
17931     showPanel : function (pan)
17932     {
17933         if(this.transition || typeof(pan) == 'undefined'){
17934             Roo.log("waiting for the transitionend");
17935             return;
17936         }
17937         
17938         if (typeof(pan) == 'number') {
17939             pan = this.tabs[pan];
17940         }
17941         
17942         if (typeof(pan) == 'string') {
17943             pan = this.getPanelByName(pan);
17944         }
17945         
17946         var cur = this.getActivePanel();
17947         
17948         if(!pan || !cur){
17949             Roo.log('pan or acitve pan is undefined');
17950             return false;
17951         }
17952         
17953         if (pan.tabId == this.getActivePanel().tabId) {
17954             return true;
17955         }
17956         
17957         if (false === cur.fireEvent('beforedeactivate')) {
17958             return false;
17959         }
17960         
17961         if(this.bullets > 0 && !Roo.isTouch){
17962             this.setActiveBullet(this.indexOfPanel(pan));
17963         }
17964         
17965         if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
17966             
17967             this.transition = true;
17968             var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur)  ? 'next' : 'prev';
17969             var lr = dir == 'next' ? 'left' : 'right';
17970             pan.el.addClass(dir); // or prev
17971             pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
17972             cur.el.addClass(lr); // or right
17973             pan.el.addClass(lr);
17974             
17975             var _this = this;
17976             cur.el.on('transitionend', function() {
17977                 Roo.log("trans end?");
17978                 
17979                 pan.el.removeClass([lr,dir]);
17980                 pan.setActive(true);
17981                 
17982                 cur.el.removeClass([lr]);
17983                 cur.setActive(false);
17984                 
17985                 _this.transition = false;
17986                 
17987             }, this, { single:  true } );
17988             
17989             return true;
17990         }
17991         
17992         cur.setActive(false);
17993         pan.setActive(true);
17994         
17995         return true;
17996         
17997     },
17998     showPanelNext : function()
17999     {
18000         var i = this.indexOfPanel(this.getActivePanel());
18001         
18002         if (i >= this.tabs.length - 1 && !this.autoslide) {
18003             return;
18004         }
18005         
18006         if (i >= this.tabs.length - 1 && this.autoslide) {
18007             i = -1;
18008         }
18009         
18010         this.showPanel(this.tabs[i+1]);
18011     },
18012     
18013     showPanelPrev : function()
18014     {
18015         var i = this.indexOfPanel(this.getActivePanel());
18016         
18017         if (i  < 1 && !this.autoslide) {
18018             return;
18019         }
18020         
18021         if (i < 1 && this.autoslide) {
18022             i = this.tabs.length;
18023         }
18024         
18025         this.showPanel(this.tabs[i-1]);
18026     },
18027     
18028     
18029     addBullet: function()
18030     {
18031         if(!this.bullets || Roo.isTouch){
18032             return;
18033         }
18034         var ctr = this.el.select('.carousel-bullets',true).first();
18035         var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18036         var bullet = ctr.createChild({
18037             cls : 'bullet bullet-' + i
18038         },ctr.dom.lastChild);
18039         
18040         
18041         var _this = this;
18042         
18043         bullet.on('click', (function(e, el, o, ii, t){
18044
18045             e.preventDefault();
18046
18047             this.showPanel(ii);
18048
18049             if(this.autoslide && this.slideFn){
18050                 clearInterval(this.slideFn);
18051                 this.slideFn = window.setInterval(function() {
18052                     _this.showPanelNext();
18053                 }, this.timer);
18054             }
18055
18056         }).createDelegate(this, [i, bullet], true));
18057                 
18058         
18059     },
18060      
18061     setActiveBullet : function(i)
18062     {
18063         if(Roo.isTouch){
18064             return;
18065         }
18066         
18067         Roo.each(this.el.select('.bullet', true).elements, function(el){
18068             el.removeClass('selected');
18069         });
18070
18071         var bullet = this.el.select('.bullet-' + i, true).first();
18072         
18073         if(!bullet){
18074             return;
18075         }
18076         
18077         bullet.addClass('selected');
18078     }
18079     
18080     
18081   
18082 });
18083
18084  
18085
18086  
18087  
18088 Roo.apply(Roo.bootstrap.TabGroup, {
18089     
18090     groups: {},
18091      /**
18092     * register a Navigation Group
18093     * @param {Roo.bootstrap.NavGroup} the navgroup to add
18094     */
18095     register : function(navgrp)
18096     {
18097         this.groups[navgrp.navId] = navgrp;
18098         
18099     },
18100     /**
18101     * fetch a Navigation Group based on the navigation ID
18102     * if one does not exist , it will get created.
18103     * @param {string} the navgroup to add
18104     * @returns {Roo.bootstrap.NavGroup} the navgroup 
18105     */
18106     get: function(navId) {
18107         if (typeof(this.groups[navId]) == 'undefined') {
18108             this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18109         }
18110         return this.groups[navId] ;
18111     }
18112     
18113     
18114     
18115 });
18116
18117  /*
18118  * - LGPL
18119  *
18120  * TabPanel
18121  * 
18122  */
18123
18124 /**
18125  * @class Roo.bootstrap.TabPanel
18126  * @extends Roo.bootstrap.Component
18127  * Bootstrap TabPanel class
18128  * @cfg {Boolean} active panel active
18129  * @cfg {String} html panel content
18130  * @cfg {String} tabId  unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18131  * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18132  * @cfg {String} href click to link..
18133  * 
18134  * 
18135  * @constructor
18136  * Create a new TabPanel
18137  * @param {Object} config The config object
18138  */
18139
18140 Roo.bootstrap.TabPanel = function(config){
18141     Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18142     this.addEvents({
18143         /**
18144              * @event changed
18145              * Fires when the active status changes
18146              * @param {Roo.bootstrap.TabPanel} this
18147              * @param {Boolean} state the new state
18148             
18149          */
18150         'changed': true,
18151         /**
18152              * @event beforedeactivate
18153              * Fires before a tab is de-activated - can be used to do validation on a form.
18154              * @param {Roo.bootstrap.TabPanel} this
18155              * @return {Boolean} false if there is an error
18156             
18157          */
18158         'beforedeactivate': true
18159      });
18160     
18161     this.tabId = this.tabId || Roo.id();
18162   
18163 };
18164
18165 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component,  {
18166     
18167     active: false,
18168     html: false,
18169     tabId: false,
18170     navId : false,
18171     href : '',
18172     
18173     getAutoCreate : function(){
18174         var cfg = {
18175             tag: 'div',
18176             // item is needed for carousel - not sure if it has any effect otherwise
18177             cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18178             html: this.html || ''
18179         };
18180         
18181         if(this.active){
18182             cfg.cls += ' active';
18183         }
18184         
18185         if(this.tabId){
18186             cfg.tabId = this.tabId;
18187         }
18188         
18189         
18190         return cfg;
18191     },
18192     
18193     initEvents:  function()
18194     {
18195         var p = this.parent();
18196         
18197         this.navId = this.navId || p.navId;
18198         
18199         if (typeof(this.navId) != 'undefined') {
18200             // not really needed.. but just in case.. parent should be a NavGroup.
18201             var tg = Roo.bootstrap.TabGroup.get(this.navId);
18202             
18203             tg.register(this);
18204             
18205             var i = tg.tabs.length - 1;
18206             
18207             if(this.active && tg.bullets > 0 && i < tg.bullets){
18208                 tg.setActiveBullet(i);
18209             }
18210         }
18211         
18212         this.el.on('click', this.onClick, this);
18213         
18214         if(Roo.isTouch){
18215             this.el.on("touchstart", this.onTouchStart, this);
18216             this.el.on("touchmove", this.onTouchMove, this);
18217             this.el.on("touchend", this.onTouchEnd, this);
18218         }
18219         
18220     },
18221     
18222     onRender : function(ct, position)
18223     {
18224         Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18225     },
18226     
18227     setActive : function(state)
18228     {
18229         Roo.log("panel - set active " + this.tabId + "=" + state);
18230         
18231         this.active = state;
18232         if (!state) {
18233             this.el.removeClass('active');
18234             
18235         } else  if (!this.el.hasClass('active')) {
18236             this.el.addClass('active');
18237         }
18238         
18239         this.fireEvent('changed', this, state);
18240     },
18241     
18242     onClick : function(e)
18243     {
18244         e.preventDefault();
18245         
18246         if(!this.href.length){
18247             return;
18248         }
18249         
18250         window.location.href = this.href;
18251     },
18252     
18253     startX : 0,
18254     startY : 0,
18255     endX : 0,
18256     endY : 0,
18257     swiping : false,
18258     
18259     onTouchStart : function(e)
18260     {
18261         this.swiping = false;
18262         
18263         this.startX = e.browserEvent.touches[0].clientX;
18264         this.startY = e.browserEvent.touches[0].clientY;
18265     },
18266     
18267     onTouchMove : function(e)
18268     {
18269         this.swiping = true;
18270         
18271         this.endX = e.browserEvent.touches[0].clientX;
18272         this.endY = e.browserEvent.touches[0].clientY;
18273     },
18274     
18275     onTouchEnd : function(e)
18276     {
18277         if(!this.swiping){
18278             this.onClick(e);
18279             return;
18280         }
18281         
18282         var tabGroup = this.parent();
18283         
18284         if(this.endX > this.startX){ // swiping right
18285             tabGroup.showPanelPrev();
18286             return;
18287         }
18288         
18289         if(this.startX > this.endX){ // swiping left
18290             tabGroup.showPanelNext();
18291             return;
18292         }
18293     }
18294     
18295     
18296 });
18297  
18298
18299  
18300
18301  /*
18302  * - LGPL
18303  *
18304  * DateField
18305  * 
18306  */
18307
18308 /**
18309  * @class Roo.bootstrap.DateField
18310  * @extends Roo.bootstrap.Input
18311  * Bootstrap DateField class
18312  * @cfg {Number} weekStart default 0
18313  * @cfg {String} viewMode default empty, (months|years)
18314  * @cfg {String} minViewMode default empty, (months|years)
18315  * @cfg {Number} startDate default -Infinity
18316  * @cfg {Number} endDate default Infinity
18317  * @cfg {Boolean} todayHighlight default false
18318  * @cfg {Boolean} todayBtn default false
18319  * @cfg {Boolean} calendarWeeks default false
18320  * @cfg {Object} daysOfWeekDisabled default empty
18321  * @cfg {Boolean} singleMode default false (true | false)
18322  * 
18323  * @cfg {Boolean} keyboardNavigation default true
18324  * @cfg {String} language default en
18325  * 
18326  * @constructor
18327  * Create a new DateField
18328  * @param {Object} config The config object
18329  */
18330
18331 Roo.bootstrap.DateField = function(config){
18332     Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18333      this.addEvents({
18334             /**
18335              * @event show
18336              * Fires when this field show.
18337              * @param {Roo.bootstrap.DateField} this
18338              * @param {Mixed} date The date value
18339              */
18340             show : true,
18341             /**
18342              * @event show
18343              * Fires when this field hide.
18344              * @param {Roo.bootstrap.DateField} this
18345              * @param {Mixed} date The date value
18346              */
18347             hide : true,
18348             /**
18349              * @event select
18350              * Fires when select a date.
18351              * @param {Roo.bootstrap.DateField} this
18352              * @param {Mixed} date The date value
18353              */
18354             select : true,
18355             /**
18356              * @event beforeselect
18357              * Fires when before select a date.
18358              * @param {Roo.bootstrap.DateField} this
18359              * @param {Mixed} date The date value
18360              */
18361             beforeselect : true
18362         });
18363 };
18364
18365 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input,  {
18366     
18367     /**
18368      * @cfg {String} format
18369      * The default date format string which can be overriden for localization support.  The format must be
18370      * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18371      */
18372     format : "m/d/y",
18373     /**
18374      * @cfg {String} altFormats
18375      * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18376      * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18377      */
18378     altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18379     
18380     weekStart : 0,
18381     
18382     viewMode : '',
18383     
18384     minViewMode : '',
18385     
18386     todayHighlight : false,
18387     
18388     todayBtn: false,
18389     
18390     language: 'en',
18391     
18392     keyboardNavigation: true,
18393     
18394     calendarWeeks: false,
18395     
18396     startDate: -Infinity,
18397     
18398     endDate: Infinity,
18399     
18400     daysOfWeekDisabled: [],
18401     
18402     _events: [],
18403     
18404     singleMode : false,
18405     
18406     UTCDate: function()
18407     {
18408         return new Date(Date.UTC.apply(Date, arguments));
18409     },
18410     
18411     UTCToday: function()
18412     {
18413         var today = new Date();
18414         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18415     },
18416     
18417     getDate: function() {
18418             var d = this.getUTCDate();
18419             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18420     },
18421     
18422     getUTCDate: function() {
18423             return this.date;
18424     },
18425     
18426     setDate: function(d) {
18427             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18428     },
18429     
18430     setUTCDate: function(d) {
18431             this.date = d;
18432             this.setValue(this.formatDate(this.date));
18433     },
18434         
18435     onRender: function(ct, position)
18436     {
18437         
18438         Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18439         
18440         this.language = this.language || 'en';
18441         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18442         this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18443         
18444         this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18445         this.format = this.format || 'm/d/y';
18446         this.isInline = false;
18447         this.isInput = true;
18448         this.component = this.el.select('.add-on', true).first() || false;
18449         this.component = (this.component && this.component.length === 0) ? false : this.component;
18450         this.hasInput = this.component && this.inputEl().length;
18451         
18452         if (typeof(this.minViewMode === 'string')) {
18453             switch (this.minViewMode) {
18454                 case 'months':
18455                     this.minViewMode = 1;
18456                     break;
18457                 case 'years':
18458                     this.minViewMode = 2;
18459                     break;
18460                 default:
18461                     this.minViewMode = 0;
18462                     break;
18463             }
18464         }
18465         
18466         if (typeof(this.viewMode === 'string')) {
18467             switch (this.viewMode) {
18468                 case 'months':
18469                     this.viewMode = 1;
18470                     break;
18471                 case 'years':
18472                     this.viewMode = 2;
18473                     break;
18474                 default:
18475                     this.viewMode = 0;
18476                     break;
18477             }
18478         }
18479                 
18480         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18481         
18482 //        this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18483         
18484         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18485         
18486         this.picker().on('mousedown', this.onMousedown, this);
18487         this.picker().on('click', this.onClick, this);
18488         
18489         this.picker().addClass('datepicker-dropdown');
18490         
18491         this.startViewMode = this.viewMode;
18492         
18493         if(this.singleMode){
18494             Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18495                 v.setVisibilityMode(Roo.Element.DISPLAY);
18496                 v.hide();
18497             });
18498             
18499             Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18500                 v.setStyle('width', '189px');
18501             });
18502         }
18503         
18504         Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18505             if(!this.calendarWeeks){
18506                 v.remove();
18507                 return;
18508             }
18509             
18510             v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18511             v.attr('colspan', function(i, val){
18512                 return parseInt(val) + 1;
18513             });
18514         });
18515                         
18516         
18517         this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18518         
18519         this.setStartDate(this.startDate);
18520         this.setEndDate(this.endDate);
18521         
18522         this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18523         
18524         this.fillDow();
18525         this.fillMonths();
18526         this.update();
18527         this.showMode();
18528         
18529         if(this.isInline) {
18530             this.show();
18531         }
18532     },
18533     
18534     picker : function()
18535     {
18536         return this.pickerEl;
18537 //        return this.el.select('.datepicker', true).first();
18538     },
18539     
18540     fillDow: function()
18541     {
18542         var dowCnt = this.weekStart;
18543         
18544         var dow = {
18545             tag: 'tr',
18546             cn: [
18547                 
18548             ]
18549         };
18550         
18551         if(this.calendarWeeks){
18552             dow.cn.push({
18553                 tag: 'th',
18554                 cls: 'cw',
18555                 html: '&nbsp;'
18556             })
18557         }
18558         
18559         while (dowCnt < this.weekStart + 7) {
18560             dow.cn.push({
18561                 tag: 'th',
18562                 cls: 'dow',
18563                 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18564             });
18565         }
18566         
18567         this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18568     },
18569     
18570     fillMonths: function()
18571     {    
18572         var i = 0;
18573         var months = this.picker().select('>.datepicker-months td', true).first();
18574         
18575         months.dom.innerHTML = '';
18576         
18577         while (i < 12) {
18578             var month = {
18579                 tag: 'span',
18580                 cls: 'month',
18581                 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18582             };
18583             
18584             months.createChild(month);
18585         }
18586         
18587     },
18588     
18589     update: function()
18590     {
18591         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;
18592         
18593         if (this.date < this.startDate) {
18594             this.viewDate = new Date(this.startDate);
18595         } else if (this.date > this.endDate) {
18596             this.viewDate = new Date(this.endDate);
18597         } else {
18598             this.viewDate = new Date(this.date);
18599         }
18600         
18601         this.fill();
18602     },
18603     
18604     fill: function() 
18605     {
18606         var d = new Date(this.viewDate),
18607                 year = d.getUTCFullYear(),
18608                 month = d.getUTCMonth(),
18609                 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18610                 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18611                 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18612                 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18613                 currentDate = this.date && this.date.valueOf(),
18614                 today = this.UTCToday();
18615         
18616         this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18617         
18618 //        this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18619         
18620 //        this.picker.select('>tfoot th.today').
18621 //                                              .text(dates[this.language].today)
18622 //                                              .toggle(this.todayBtn !== false);
18623     
18624         this.updateNavArrows();
18625         this.fillMonths();
18626                                                 
18627         var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18628         
18629         day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18630          
18631         prevMonth.setUTCDate(day);
18632         
18633         prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18634         
18635         var nextMonth = new Date(prevMonth);
18636         
18637         nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18638         
18639         nextMonth = nextMonth.valueOf();
18640         
18641         var fillMonths = false;
18642         
18643         this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18644         
18645         while(prevMonth.valueOf() <= nextMonth) {
18646             var clsName = '';
18647             
18648             if (prevMonth.getUTCDay() === this.weekStart) {
18649                 if(fillMonths){
18650                     this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18651                 }
18652                     
18653                 fillMonths = {
18654                     tag: 'tr',
18655                     cn: []
18656                 };
18657                 
18658                 if(this.calendarWeeks){
18659                     // ISO 8601: First week contains first thursday.
18660                     // ISO also states week starts on Monday, but we can be more abstract here.
18661                     var
18662                     // Start of current week: based on weekstart/current date
18663                     ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18664                     // Thursday of this week
18665                     th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18666                     // First Thursday of year, year from thursday
18667                     yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18668                     // Calendar week: ms between thursdays, div ms per day, div 7 days
18669                     calWeek =  (th - yth) / 864e5 / 7 + 1;
18670                     
18671                     fillMonths.cn.push({
18672                         tag: 'td',
18673                         cls: 'cw',
18674                         html: calWeek
18675                     });
18676                 }
18677             }
18678             
18679             if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18680                 clsName += ' old';
18681             } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18682                 clsName += ' new';
18683             }
18684             if (this.todayHighlight &&
18685                 prevMonth.getUTCFullYear() == today.getFullYear() &&
18686                 prevMonth.getUTCMonth() == today.getMonth() &&
18687                 prevMonth.getUTCDate() == today.getDate()) {
18688                 clsName += ' today';
18689             }
18690             
18691             if (currentDate && prevMonth.valueOf() === currentDate) {
18692                 clsName += ' active';
18693             }
18694             
18695             if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18696                     this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18697                     clsName += ' disabled';
18698             }
18699             
18700             fillMonths.cn.push({
18701                 tag: 'td',
18702                 cls: 'day ' + clsName,
18703                 html: prevMonth.getDate()
18704             });
18705             
18706             prevMonth.setDate(prevMonth.getDate()+1);
18707         }
18708           
18709         var currentYear = this.date && this.date.getUTCFullYear();
18710         var currentMonth = this.date && this.date.getUTCMonth();
18711         
18712         this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18713         
18714         Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18715             v.removeClass('active');
18716             
18717             if(currentYear === year && k === currentMonth){
18718                 v.addClass('active');
18719             }
18720             
18721             if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
18722                 v.addClass('disabled');
18723             }
18724             
18725         });
18726         
18727         
18728         year = parseInt(year/10, 10) * 10;
18729         
18730         this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
18731         
18732         this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
18733         
18734         year -= 1;
18735         for (var i = -1; i < 11; i++) {
18736             this.picker().select('>.datepicker-years tbody td',true).first().createChild({
18737                 tag: 'span',
18738                 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
18739                 html: year
18740             });
18741             
18742             year += 1;
18743         }
18744     },
18745     
18746     showMode: function(dir) 
18747     {
18748         if (dir) {
18749             this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
18750         }
18751         
18752         Roo.each(this.picker().select('>div',true).elements, function(v){
18753             v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18754             v.hide();
18755         });
18756         this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
18757     },
18758     
18759     place: function()
18760     {
18761         if(this.isInline) {
18762             return;
18763         }
18764         
18765         this.picker().removeClass(['bottom', 'top']);
18766         
18767         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
18768             /*
18769              * place to the top of element!
18770              *
18771              */
18772             
18773             this.picker().addClass('top');
18774             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
18775             
18776             return;
18777         }
18778         
18779         this.picker().addClass('bottom');
18780         
18781         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
18782     },
18783     
18784     parseDate : function(value)
18785     {
18786         if(!value || value instanceof Date){
18787             return value;
18788         }
18789         var v = Date.parseDate(value, this.format);
18790         if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
18791             v = Date.parseDate(value, 'Y-m-d');
18792         }
18793         if(!v && this.altFormats){
18794             if(!this.altFormatsArray){
18795                 this.altFormatsArray = this.altFormats.split("|");
18796             }
18797             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
18798                 v = Date.parseDate(value, this.altFormatsArray[i]);
18799             }
18800         }
18801         return v;
18802     },
18803     
18804     formatDate : function(date, fmt)
18805     {   
18806         return (!date || !(date instanceof Date)) ?
18807         date : date.dateFormat(fmt || this.format);
18808     },
18809     
18810     onFocus : function()
18811     {
18812         Roo.bootstrap.DateField.superclass.onFocus.call(this);
18813         this.show();
18814     },
18815     
18816     onBlur : function()
18817     {
18818         Roo.bootstrap.DateField.superclass.onBlur.call(this);
18819         
18820         var d = this.inputEl().getValue();
18821         
18822         this.setValue(d);
18823                 
18824         this.hide();
18825     },
18826     
18827     show : function()
18828     {
18829         this.picker().show();
18830         this.update();
18831         this.place();
18832         
18833         this.fireEvent('show', this, this.date);
18834     },
18835     
18836     hide : function()
18837     {
18838         if(this.isInline) {
18839             return;
18840         }
18841         this.picker().hide();
18842         this.viewMode = this.startViewMode;
18843         this.showMode();
18844         
18845         this.fireEvent('hide', this, this.date);
18846         
18847     },
18848     
18849     onMousedown: function(e)
18850     {
18851         e.stopPropagation();
18852         e.preventDefault();
18853     },
18854     
18855     keyup: function(e)
18856     {
18857         Roo.bootstrap.DateField.superclass.keyup.call(this);
18858         this.update();
18859     },
18860
18861     setValue: function(v)
18862     {
18863         if(this.fireEvent('beforeselect', this, v) !== false){
18864             var d = new Date(this.parseDate(v) ).clearTime();
18865         
18866             if(isNaN(d.getTime())){
18867                 this.date = this.viewDate = '';
18868                 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
18869                 return;
18870             }
18871
18872             v = this.formatDate(d);
18873
18874             Roo.bootstrap.DateField.superclass.setValue.call(this, v);
18875
18876             this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
18877
18878             this.update();
18879
18880             this.fireEvent('select', this, this.date);
18881         }
18882     },
18883     
18884     getValue: function()
18885     {
18886         return this.formatDate(this.date);
18887     },
18888     
18889     fireKey: function(e)
18890     {
18891         if (!this.picker().isVisible()){
18892             if (e.keyCode == 27) { // allow escape to hide and re-show picker
18893                 this.show();
18894             }
18895             return;
18896         }
18897         
18898         var dateChanged = false,
18899         dir, day, month,
18900         newDate, newViewDate;
18901         
18902         switch(e.keyCode){
18903             case 27: // escape
18904                 this.hide();
18905                 e.preventDefault();
18906                 break;
18907             case 37: // left
18908             case 39: // right
18909                 if (!this.keyboardNavigation) {
18910                     break;
18911                 }
18912                 dir = e.keyCode == 37 ? -1 : 1;
18913                 
18914                 if (e.ctrlKey){
18915                     newDate = this.moveYear(this.date, dir);
18916                     newViewDate = this.moveYear(this.viewDate, dir);
18917                 } else if (e.shiftKey){
18918                     newDate = this.moveMonth(this.date, dir);
18919                     newViewDate = this.moveMonth(this.viewDate, dir);
18920                 } else {
18921                     newDate = new Date(this.date);
18922                     newDate.setUTCDate(this.date.getUTCDate() + dir);
18923                     newViewDate = new Date(this.viewDate);
18924                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
18925                 }
18926                 if (this.dateWithinRange(newDate)){
18927                     this.date = newDate;
18928                     this.viewDate = newViewDate;
18929                     this.setValue(this.formatDate(this.date));
18930 //                    this.update();
18931                     e.preventDefault();
18932                     dateChanged = true;
18933                 }
18934                 break;
18935             case 38: // up
18936             case 40: // down
18937                 if (!this.keyboardNavigation) {
18938                     break;
18939                 }
18940                 dir = e.keyCode == 38 ? -1 : 1;
18941                 if (e.ctrlKey){
18942                     newDate = this.moveYear(this.date, dir);
18943                     newViewDate = this.moveYear(this.viewDate, dir);
18944                 } else if (e.shiftKey){
18945                     newDate = this.moveMonth(this.date, dir);
18946                     newViewDate = this.moveMonth(this.viewDate, dir);
18947                 } else {
18948                     newDate = new Date(this.date);
18949                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
18950                     newViewDate = new Date(this.viewDate);
18951                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
18952                 }
18953                 if (this.dateWithinRange(newDate)){
18954                     this.date = newDate;
18955                     this.viewDate = newViewDate;
18956                     this.setValue(this.formatDate(this.date));
18957 //                    this.update();
18958                     e.preventDefault();
18959                     dateChanged = true;
18960                 }
18961                 break;
18962             case 13: // enter
18963                 this.setValue(this.formatDate(this.date));
18964                 this.hide();
18965                 e.preventDefault();
18966                 break;
18967             case 9: // tab
18968                 this.setValue(this.formatDate(this.date));
18969                 this.hide();
18970                 break;
18971             case 16: // shift
18972             case 17: // ctrl
18973             case 18: // alt
18974                 break;
18975             default :
18976                 this.hide();
18977                 
18978         }
18979     },
18980     
18981     
18982     onClick: function(e) 
18983     {
18984         e.stopPropagation();
18985         e.preventDefault();
18986         
18987         var target = e.getTarget();
18988         
18989         if(target.nodeName.toLowerCase() === 'i'){
18990             target = Roo.get(target).dom.parentNode;
18991         }
18992         
18993         var nodeName = target.nodeName;
18994         var className = target.className;
18995         var html = target.innerHTML;
18996         //Roo.log(nodeName);
18997         
18998         switch(nodeName.toLowerCase()) {
18999             case 'th':
19000                 switch(className) {
19001                     case 'switch':
19002                         this.showMode(1);
19003                         break;
19004                     case 'prev':
19005                     case 'next':
19006                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19007                         switch(this.viewMode){
19008                                 case 0:
19009                                         this.viewDate = this.moveMonth(this.viewDate, dir);
19010                                         break;
19011                                 case 1:
19012                                 case 2:
19013                                         this.viewDate = this.moveYear(this.viewDate, dir);
19014                                         break;
19015                         }
19016                         this.fill();
19017                         break;
19018                     case 'today':
19019                         var date = new Date();
19020                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19021 //                        this.fill()
19022                         this.setValue(this.formatDate(this.date));
19023                         
19024                         this.hide();
19025                         break;
19026                 }
19027                 break;
19028             case 'span':
19029                 if (className.indexOf('disabled') < 0) {
19030                     this.viewDate.setUTCDate(1);
19031                     if (className.indexOf('month') > -1) {
19032                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19033                     } else {
19034                         var year = parseInt(html, 10) || 0;
19035                         this.viewDate.setUTCFullYear(year);
19036                         
19037                     }
19038                     
19039                     if(this.singleMode){
19040                         this.setValue(this.formatDate(this.viewDate));
19041                         this.hide();
19042                         return;
19043                     }
19044                     
19045                     this.showMode(-1);
19046                     this.fill();
19047                 }
19048                 break;
19049                 
19050             case 'td':
19051                 //Roo.log(className);
19052                 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19053                     var day = parseInt(html, 10) || 1;
19054                     var year = this.viewDate.getUTCFullYear(),
19055                         month = this.viewDate.getUTCMonth();
19056
19057                     if (className.indexOf('old') > -1) {
19058                         if(month === 0 ){
19059                             month = 11;
19060                             year -= 1;
19061                         }else{
19062                             month -= 1;
19063                         }
19064                     } else if (className.indexOf('new') > -1) {
19065                         if (month == 11) {
19066                             month = 0;
19067                             year += 1;
19068                         } else {
19069                             month += 1;
19070                         }
19071                     }
19072                     //Roo.log([year,month,day]);
19073                     this.date = this.UTCDate(year, month, day,0,0,0,0);
19074                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19075 //                    this.fill();
19076                     //Roo.log(this.formatDate(this.date));
19077                     this.setValue(this.formatDate(this.date));
19078                     this.hide();
19079                 }
19080                 break;
19081         }
19082     },
19083     
19084     setStartDate: function(startDate)
19085     {
19086         this.startDate = startDate || -Infinity;
19087         if (this.startDate !== -Infinity) {
19088             this.startDate = this.parseDate(this.startDate);
19089         }
19090         this.update();
19091         this.updateNavArrows();
19092     },
19093
19094     setEndDate: function(endDate)
19095     {
19096         this.endDate = endDate || Infinity;
19097         if (this.endDate !== Infinity) {
19098             this.endDate = this.parseDate(this.endDate);
19099         }
19100         this.update();
19101         this.updateNavArrows();
19102     },
19103     
19104     setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19105     {
19106         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19107         if (typeof(this.daysOfWeekDisabled) !== 'object') {
19108             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19109         }
19110         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19111             return parseInt(d, 10);
19112         });
19113         this.update();
19114         this.updateNavArrows();
19115     },
19116     
19117     updateNavArrows: function() 
19118     {
19119         if(this.singleMode){
19120             return;
19121         }
19122         
19123         var d = new Date(this.viewDate),
19124         year = d.getUTCFullYear(),
19125         month = d.getUTCMonth();
19126         
19127         Roo.each(this.picker().select('.prev', true).elements, function(v){
19128             v.show();
19129             switch (this.viewMode) {
19130                 case 0:
19131
19132                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19133                         v.hide();
19134                     }
19135                     break;
19136                 case 1:
19137                 case 2:
19138                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19139                         v.hide();
19140                     }
19141                     break;
19142             }
19143         });
19144         
19145         Roo.each(this.picker().select('.next', true).elements, function(v){
19146             v.show();
19147             switch (this.viewMode) {
19148                 case 0:
19149
19150                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19151                         v.hide();
19152                     }
19153                     break;
19154                 case 1:
19155                 case 2:
19156                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19157                         v.hide();
19158                     }
19159                     break;
19160             }
19161         })
19162     },
19163     
19164     moveMonth: function(date, dir)
19165     {
19166         if (!dir) {
19167             return date;
19168         }
19169         var new_date = new Date(date.valueOf()),
19170         day = new_date.getUTCDate(),
19171         month = new_date.getUTCMonth(),
19172         mag = Math.abs(dir),
19173         new_month, test;
19174         dir = dir > 0 ? 1 : -1;
19175         if (mag == 1){
19176             test = dir == -1
19177             // If going back one month, make sure month is not current month
19178             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19179             ? function(){
19180                 return new_date.getUTCMonth() == month;
19181             }
19182             // If going forward one month, make sure month is as expected
19183             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19184             : function(){
19185                 return new_date.getUTCMonth() != new_month;
19186             };
19187             new_month = month + dir;
19188             new_date.setUTCMonth(new_month);
19189             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19190             if (new_month < 0 || new_month > 11) {
19191                 new_month = (new_month + 12) % 12;
19192             }
19193         } else {
19194             // For magnitudes >1, move one month at a time...
19195             for (var i=0; i<mag; i++) {
19196                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19197                 new_date = this.moveMonth(new_date, dir);
19198             }
19199             // ...then reset the day, keeping it in the new month
19200             new_month = new_date.getUTCMonth();
19201             new_date.setUTCDate(day);
19202             test = function(){
19203                 return new_month != new_date.getUTCMonth();
19204             };
19205         }
19206         // Common date-resetting loop -- if date is beyond end of month, make it
19207         // end of month
19208         while (test()){
19209             new_date.setUTCDate(--day);
19210             new_date.setUTCMonth(new_month);
19211         }
19212         return new_date;
19213     },
19214
19215     moveYear: function(date, dir)
19216     {
19217         return this.moveMonth(date, dir*12);
19218     },
19219
19220     dateWithinRange: function(date)
19221     {
19222         return date >= this.startDate && date <= this.endDate;
19223     },
19224
19225     
19226     remove: function() 
19227     {
19228         this.picker().remove();
19229     },
19230     
19231     validateValue : function(value)
19232     {
19233         if(this.getVisibilityEl().hasClass('hidden')){
19234             return true;
19235         }
19236         
19237         if(value.length < 1)  {
19238             if(this.allowBlank){
19239                 return true;
19240             }
19241             return false;
19242         }
19243         
19244         if(value.length < this.minLength){
19245             return false;
19246         }
19247         if(value.length > this.maxLength){
19248             return false;
19249         }
19250         if(this.vtype){
19251             var vt = Roo.form.VTypes;
19252             if(!vt[this.vtype](value, this)){
19253                 return false;
19254             }
19255         }
19256         if(typeof this.validator == "function"){
19257             var msg = this.validator(value);
19258             if(msg !== true){
19259                 return false;
19260             }
19261         }
19262         
19263         if(this.regex && !this.regex.test(value)){
19264             return false;
19265         }
19266         
19267         if(typeof(this.parseDate(value)) == 'undefined'){
19268             return false;
19269         }
19270         
19271         if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19272             return false;
19273         }      
19274         
19275         if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19276             return false;
19277         } 
19278         
19279         
19280         return true;
19281     },
19282     
19283     reset : function()
19284     {
19285         this.date = this.viewDate = '';
19286         
19287         Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19288     },
19289     
19290     setVisible : function(visible)
19291     {
19292         if(!this.getEl()){
19293             return;
19294         }
19295         
19296         this.getEl().removeClass('hidden');
19297         
19298         if(visible){
19299             return;
19300         }
19301         
19302         this.getEl().addClass('hidden');
19303     }
19304    
19305 });
19306
19307 Roo.apply(Roo.bootstrap.DateField,  {
19308     
19309     head : {
19310         tag: 'thead',
19311         cn: [
19312         {
19313             tag: 'tr',
19314             cn: [
19315             {
19316                 tag: 'th',
19317                 cls: 'prev',
19318                 html: '<i class="fa fa-arrow-left"/>'
19319             },
19320             {
19321                 tag: 'th',
19322                 cls: 'switch',
19323                 colspan: '5'
19324             },
19325             {
19326                 tag: 'th',
19327                 cls: 'next',
19328                 html: '<i class="fa fa-arrow-right"/>'
19329             }
19330
19331             ]
19332         }
19333         ]
19334     },
19335     
19336     content : {
19337         tag: 'tbody',
19338         cn: [
19339         {
19340             tag: 'tr',
19341             cn: [
19342             {
19343                 tag: 'td',
19344                 colspan: '7'
19345             }
19346             ]
19347         }
19348         ]
19349     },
19350     
19351     footer : {
19352         tag: 'tfoot',
19353         cn: [
19354         {
19355             tag: 'tr',
19356             cn: [
19357             {
19358                 tag: 'th',
19359                 colspan: '7',
19360                 cls: 'today'
19361             }
19362                     
19363             ]
19364         }
19365         ]
19366     },
19367     
19368     dates:{
19369         en: {
19370             days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19371             daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19372             daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19373             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19374             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19375             today: "Today"
19376         }
19377     },
19378     
19379     modes: [
19380     {
19381         clsName: 'days',
19382         navFnc: 'Month',
19383         navStep: 1
19384     },
19385     {
19386         clsName: 'months',
19387         navFnc: 'FullYear',
19388         navStep: 1
19389     },
19390     {
19391         clsName: 'years',
19392         navFnc: 'FullYear',
19393         navStep: 10
19394     }]
19395 });
19396
19397 Roo.apply(Roo.bootstrap.DateField,  {
19398   
19399     template : {
19400         tag: 'div',
19401         cls: 'datepicker dropdown-menu roo-dynamic',
19402         cn: [
19403         {
19404             tag: 'div',
19405             cls: 'datepicker-days',
19406             cn: [
19407             {
19408                 tag: 'table',
19409                 cls: 'table-condensed',
19410                 cn:[
19411                 Roo.bootstrap.DateField.head,
19412                 {
19413                     tag: 'tbody'
19414                 },
19415                 Roo.bootstrap.DateField.footer
19416                 ]
19417             }
19418             ]
19419         },
19420         {
19421             tag: 'div',
19422             cls: 'datepicker-months',
19423             cn: [
19424             {
19425                 tag: 'table',
19426                 cls: 'table-condensed',
19427                 cn:[
19428                 Roo.bootstrap.DateField.head,
19429                 Roo.bootstrap.DateField.content,
19430                 Roo.bootstrap.DateField.footer
19431                 ]
19432             }
19433             ]
19434         },
19435         {
19436             tag: 'div',
19437             cls: 'datepicker-years',
19438             cn: [
19439             {
19440                 tag: 'table',
19441                 cls: 'table-condensed',
19442                 cn:[
19443                 Roo.bootstrap.DateField.head,
19444                 Roo.bootstrap.DateField.content,
19445                 Roo.bootstrap.DateField.footer
19446                 ]
19447             }
19448             ]
19449         }
19450         ]
19451     }
19452 });
19453
19454  
19455
19456  /*
19457  * - LGPL
19458  *
19459  * TimeField
19460  * 
19461  */
19462
19463 /**
19464  * @class Roo.bootstrap.TimeField
19465  * @extends Roo.bootstrap.Input
19466  * Bootstrap DateField class
19467  * 
19468  * 
19469  * @constructor
19470  * Create a new TimeField
19471  * @param {Object} config The config object
19472  */
19473
19474 Roo.bootstrap.TimeField = function(config){
19475     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19476     this.addEvents({
19477             /**
19478              * @event show
19479              * Fires when this field show.
19480              * @param {Roo.bootstrap.DateField} thisthis
19481              * @param {Mixed} date The date value
19482              */
19483             show : true,
19484             /**
19485              * @event show
19486              * Fires when this field hide.
19487              * @param {Roo.bootstrap.DateField} this
19488              * @param {Mixed} date The date value
19489              */
19490             hide : true,
19491             /**
19492              * @event select
19493              * Fires when select a date.
19494              * @param {Roo.bootstrap.DateField} this
19495              * @param {Mixed} date The date value
19496              */
19497             select : true
19498         });
19499 };
19500
19501 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
19502     
19503     /**
19504      * @cfg {String} format
19505      * The default time format string which can be overriden for localization support.  The format must be
19506      * valid according to {@link Date#parseDate} (defaults to 'H:i').
19507      */
19508     format : "H:i",
19509        
19510     onRender: function(ct, position)
19511     {
19512         
19513         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19514                 
19515         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19516         
19517         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19518         
19519         this.pop = this.picker().select('>.datepicker-time',true).first();
19520         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19521         
19522         this.picker().on('mousedown', this.onMousedown, this);
19523         this.picker().on('click', this.onClick, this);
19524         
19525         this.picker().addClass('datepicker-dropdown');
19526     
19527         this.fillTime();
19528         this.update();
19529             
19530         this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19531         this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19532         this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19533         this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19534         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19535         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19536
19537     },
19538     
19539     fireKey: function(e){
19540         if (!this.picker().isVisible()){
19541             if (e.keyCode == 27) { // allow escape to hide and re-show picker
19542                 this.show();
19543             }
19544             return;
19545         }
19546
19547         e.preventDefault();
19548         
19549         switch(e.keyCode){
19550             case 27: // escape
19551                 this.hide();
19552                 break;
19553             case 37: // left
19554             case 39: // right
19555                 this.onTogglePeriod();
19556                 break;
19557             case 38: // up
19558                 this.onIncrementMinutes();
19559                 break;
19560             case 40: // down
19561                 this.onDecrementMinutes();
19562                 break;
19563             case 13: // enter
19564             case 9: // tab
19565                 this.setTime();
19566                 break;
19567         }
19568     },
19569     
19570     onClick: function(e) {
19571         e.stopPropagation();
19572         e.preventDefault();
19573     },
19574     
19575     picker : function()
19576     {
19577         return this.el.select('.datepicker', true).first();
19578     },
19579     
19580     fillTime: function()
19581     {    
19582         var time = this.pop.select('tbody', true).first();
19583         
19584         time.dom.innerHTML = '';
19585         
19586         time.createChild({
19587             tag: 'tr',
19588             cn: [
19589                 {
19590                     tag: 'td',
19591                     cn: [
19592                         {
19593                             tag: 'a',
19594                             href: '#',
19595                             cls: 'btn',
19596                             cn: [
19597                                 {
19598                                     tag: 'span',
19599                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
19600                                 }
19601                             ]
19602                         } 
19603                     ]
19604                 },
19605                 {
19606                     tag: 'td',
19607                     cls: 'separator'
19608                 },
19609                 {
19610                     tag: 'td',
19611                     cn: [
19612                         {
19613                             tag: 'a',
19614                             href: '#',
19615                             cls: 'btn',
19616                             cn: [
19617                                 {
19618                                     tag: 'span',
19619                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
19620                                 }
19621                             ]
19622                         }
19623                     ]
19624                 },
19625                 {
19626                     tag: 'td',
19627                     cls: 'separator'
19628                 }
19629             ]
19630         });
19631         
19632         time.createChild({
19633             tag: 'tr',
19634             cn: [
19635                 {
19636                     tag: 'td',
19637                     cn: [
19638                         {
19639                             tag: 'span',
19640                             cls: 'timepicker-hour',
19641                             html: '00'
19642                         }  
19643                     ]
19644                 },
19645                 {
19646                     tag: 'td',
19647                     cls: 'separator',
19648                     html: ':'
19649                 },
19650                 {
19651                     tag: 'td',
19652                     cn: [
19653                         {
19654                             tag: 'span',
19655                             cls: 'timepicker-minute',
19656                             html: '00'
19657                         }  
19658                     ]
19659                 },
19660                 {
19661                     tag: 'td',
19662                     cls: 'separator'
19663                 },
19664                 {
19665                     tag: 'td',
19666                     cn: [
19667                         {
19668                             tag: 'button',
19669                             type: 'button',
19670                             cls: 'btn btn-primary period',
19671                             html: 'AM'
19672                             
19673                         }
19674                     ]
19675                 }
19676             ]
19677         });
19678         
19679         time.createChild({
19680             tag: 'tr',
19681             cn: [
19682                 {
19683                     tag: 'td',
19684                     cn: [
19685                         {
19686                             tag: 'a',
19687                             href: '#',
19688                             cls: 'btn',
19689                             cn: [
19690                                 {
19691                                     tag: 'span',
19692                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
19693                                 }
19694                             ]
19695                         }
19696                     ]
19697                 },
19698                 {
19699                     tag: 'td',
19700                     cls: 'separator'
19701                 },
19702                 {
19703                     tag: 'td',
19704                     cn: [
19705                         {
19706                             tag: 'a',
19707                             href: '#',
19708                             cls: 'btn',
19709                             cn: [
19710                                 {
19711                                     tag: 'span',
19712                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
19713                                 }
19714                             ]
19715                         }
19716                     ]
19717                 },
19718                 {
19719                     tag: 'td',
19720                     cls: 'separator'
19721                 }
19722             ]
19723         });
19724         
19725     },
19726     
19727     update: function()
19728     {
19729         
19730         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
19731         
19732         this.fill();
19733     },
19734     
19735     fill: function() 
19736     {
19737         var hours = this.time.getHours();
19738         var minutes = this.time.getMinutes();
19739         var period = 'AM';
19740         
19741         if(hours > 11){
19742             period = 'PM';
19743         }
19744         
19745         if(hours == 0){
19746             hours = 12;
19747         }
19748         
19749         
19750         if(hours > 12){
19751             hours = hours - 12;
19752         }
19753         
19754         if(hours < 10){
19755             hours = '0' + hours;
19756         }
19757         
19758         if(minutes < 10){
19759             minutes = '0' + minutes;
19760         }
19761         
19762         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
19763         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
19764         this.pop.select('button', true).first().dom.innerHTML = period;
19765         
19766     },
19767     
19768     place: function()
19769     {   
19770         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
19771         
19772         var cls = ['bottom'];
19773         
19774         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
19775             cls.pop();
19776             cls.push('top');
19777         }
19778         
19779         cls.push('right');
19780         
19781         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
19782             cls.pop();
19783             cls.push('left');
19784         }
19785         
19786         this.picker().addClass(cls.join('-'));
19787         
19788         var _this = this;
19789         
19790         Roo.each(cls, function(c){
19791             if(c == 'bottom'){
19792                 _this.picker().setTop(_this.inputEl().getHeight());
19793                 return;
19794             }
19795             if(c == 'top'){
19796                 _this.picker().setTop(0 - _this.picker().getHeight());
19797                 return;
19798             }
19799             
19800             if(c == 'left'){
19801                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
19802                 return;
19803             }
19804             if(c == 'right'){
19805                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
19806                 return;
19807             }
19808         });
19809         
19810     },
19811   
19812     onFocus : function()
19813     {
19814         Roo.bootstrap.TimeField.superclass.onFocus.call(this);
19815         this.show();
19816     },
19817     
19818     onBlur : function()
19819     {
19820         Roo.bootstrap.TimeField.superclass.onBlur.call(this);
19821         this.hide();
19822     },
19823     
19824     show : function()
19825     {
19826         this.picker().show();
19827         this.pop.show();
19828         this.update();
19829         this.place();
19830         
19831         this.fireEvent('show', this, this.date);
19832     },
19833     
19834     hide : function()
19835     {
19836         this.picker().hide();
19837         this.pop.hide();
19838         
19839         this.fireEvent('hide', this, this.date);
19840     },
19841     
19842     setTime : function()
19843     {
19844         this.hide();
19845         this.setValue(this.time.format(this.format));
19846         
19847         this.fireEvent('select', this, this.date);
19848         
19849         
19850     },
19851     
19852     onMousedown: function(e){
19853         e.stopPropagation();
19854         e.preventDefault();
19855     },
19856     
19857     onIncrementHours: function()
19858     {
19859         Roo.log('onIncrementHours');
19860         this.time = this.time.add(Date.HOUR, 1);
19861         this.update();
19862         
19863     },
19864     
19865     onDecrementHours: function()
19866     {
19867         Roo.log('onDecrementHours');
19868         this.time = this.time.add(Date.HOUR, -1);
19869         this.update();
19870     },
19871     
19872     onIncrementMinutes: function()
19873     {
19874         Roo.log('onIncrementMinutes');
19875         this.time = this.time.add(Date.MINUTE, 1);
19876         this.update();
19877     },
19878     
19879     onDecrementMinutes: function()
19880     {
19881         Roo.log('onDecrementMinutes');
19882         this.time = this.time.add(Date.MINUTE, -1);
19883         this.update();
19884     },
19885     
19886     onTogglePeriod: function()
19887     {
19888         Roo.log('onTogglePeriod');
19889         this.time = this.time.add(Date.HOUR, 12);
19890         this.update();
19891     }
19892     
19893    
19894 });
19895
19896 Roo.apply(Roo.bootstrap.TimeField,  {
19897     
19898     content : {
19899         tag: 'tbody',
19900         cn: [
19901             {
19902                 tag: 'tr',
19903                 cn: [
19904                 {
19905                     tag: 'td',
19906                     colspan: '7'
19907                 }
19908                 ]
19909             }
19910         ]
19911     },
19912     
19913     footer : {
19914         tag: 'tfoot',
19915         cn: [
19916             {
19917                 tag: 'tr',
19918                 cn: [
19919                 {
19920                     tag: 'th',
19921                     colspan: '7',
19922                     cls: '',
19923                     cn: [
19924                         {
19925                             tag: 'button',
19926                             cls: 'btn btn-info ok',
19927                             html: 'OK'
19928                         }
19929                     ]
19930                 }
19931
19932                 ]
19933             }
19934         ]
19935     }
19936 });
19937
19938 Roo.apply(Roo.bootstrap.TimeField,  {
19939   
19940     template : {
19941         tag: 'div',
19942         cls: 'datepicker dropdown-menu',
19943         cn: [
19944             {
19945                 tag: 'div',
19946                 cls: 'datepicker-time',
19947                 cn: [
19948                 {
19949                     tag: 'table',
19950                     cls: 'table-condensed',
19951                     cn:[
19952                     Roo.bootstrap.TimeField.content,
19953                     Roo.bootstrap.TimeField.footer
19954                     ]
19955                 }
19956                 ]
19957             }
19958         ]
19959     }
19960 });
19961
19962  
19963
19964  /*
19965  * - LGPL
19966  *
19967  * MonthField
19968  * 
19969  */
19970
19971 /**
19972  * @class Roo.bootstrap.MonthField
19973  * @extends Roo.bootstrap.Input
19974  * Bootstrap MonthField class
19975  * 
19976  * @cfg {String} language default en
19977  * 
19978  * @constructor
19979  * Create a new MonthField
19980  * @param {Object} config The config object
19981  */
19982
19983 Roo.bootstrap.MonthField = function(config){
19984     Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
19985     
19986     this.addEvents({
19987         /**
19988          * @event show
19989          * Fires when this field show.
19990          * @param {Roo.bootstrap.MonthField} this
19991          * @param {Mixed} date The date value
19992          */
19993         show : true,
19994         /**
19995          * @event show
19996          * Fires when this field hide.
19997          * @param {Roo.bootstrap.MonthField} this
19998          * @param {Mixed} date The date value
19999          */
20000         hide : true,
20001         /**
20002          * @event select
20003          * Fires when select a date.
20004          * @param {Roo.bootstrap.MonthField} this
20005          * @param {String} oldvalue The old value
20006          * @param {String} newvalue The new value
20007          */
20008         select : true
20009     });
20010 };
20011
20012 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input,  {
20013     
20014     onRender: function(ct, position)
20015     {
20016         
20017         Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20018         
20019         this.language = this.language || 'en';
20020         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20021         this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20022         
20023         this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20024         this.isInline = false;
20025         this.isInput = true;
20026         this.component = this.el.select('.add-on', true).first() || false;
20027         this.component = (this.component && this.component.length === 0) ? false : this.component;
20028         this.hasInput = this.component && this.inputEL().length;
20029         
20030         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20031         
20032         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20033         
20034         this.picker().on('mousedown', this.onMousedown, this);
20035         this.picker().on('click', this.onClick, this);
20036         
20037         this.picker().addClass('datepicker-dropdown');
20038         
20039         Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20040             v.setStyle('width', '189px');
20041         });
20042         
20043         this.fillMonths();
20044         
20045         this.update();
20046         
20047         if(this.isInline) {
20048             this.show();
20049         }
20050         
20051     },
20052     
20053     setValue: function(v, suppressEvent)
20054     {   
20055         var o = this.getValue();
20056         
20057         Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20058         
20059         this.update();
20060
20061         if(suppressEvent !== true){
20062             this.fireEvent('select', this, o, v);
20063         }
20064         
20065     },
20066     
20067     getValue: function()
20068     {
20069         return this.value;
20070     },
20071     
20072     onClick: function(e) 
20073     {
20074         e.stopPropagation();
20075         e.preventDefault();
20076         
20077         var target = e.getTarget();
20078         
20079         if(target.nodeName.toLowerCase() === 'i'){
20080             target = Roo.get(target).dom.parentNode;
20081         }
20082         
20083         var nodeName = target.nodeName;
20084         var className = target.className;
20085         var html = target.innerHTML;
20086         
20087         if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20088             return;
20089         }
20090         
20091         this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20092         
20093         this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20094         
20095         this.hide();
20096                         
20097     },
20098     
20099     picker : function()
20100     {
20101         return this.pickerEl;
20102     },
20103     
20104     fillMonths: function()
20105     {    
20106         var i = 0;
20107         var months = this.picker().select('>.datepicker-months td', true).first();
20108         
20109         months.dom.innerHTML = '';
20110         
20111         while (i < 12) {
20112             var month = {
20113                 tag: 'span',
20114                 cls: 'month',
20115                 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20116             };
20117             
20118             months.createChild(month);
20119         }
20120         
20121     },
20122     
20123     update: function()
20124     {
20125         var _this = this;
20126         
20127         if(typeof(this.vIndex) == 'undefined' && this.value.length){
20128             this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20129         }
20130         
20131         Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20132             e.removeClass('active');
20133             
20134             if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20135                 e.addClass('active');
20136             }
20137         })
20138     },
20139     
20140     place: function()
20141     {
20142         if(this.isInline) {
20143             return;
20144         }
20145         
20146         this.picker().removeClass(['bottom', 'top']);
20147         
20148         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20149             /*
20150              * place to the top of element!
20151              *
20152              */
20153             
20154             this.picker().addClass('top');
20155             this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20156             
20157             return;
20158         }
20159         
20160         this.picker().addClass('bottom');
20161         
20162         this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20163     },
20164     
20165     onFocus : function()
20166     {
20167         Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20168         this.show();
20169     },
20170     
20171     onBlur : function()
20172     {
20173         Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20174         
20175         var d = this.inputEl().getValue();
20176         
20177         this.setValue(d);
20178                 
20179         this.hide();
20180     },
20181     
20182     show : function()
20183     {
20184         this.picker().show();
20185         this.picker().select('>.datepicker-months', true).first().show();
20186         this.update();
20187         this.place();
20188         
20189         this.fireEvent('show', this, this.date);
20190     },
20191     
20192     hide : function()
20193     {
20194         if(this.isInline) {
20195             return;
20196         }
20197         this.picker().hide();
20198         this.fireEvent('hide', this, this.date);
20199         
20200     },
20201     
20202     onMousedown: function(e)
20203     {
20204         e.stopPropagation();
20205         e.preventDefault();
20206     },
20207     
20208     keyup: function(e)
20209     {
20210         Roo.bootstrap.MonthField.superclass.keyup.call(this);
20211         this.update();
20212     },
20213
20214     fireKey: function(e)
20215     {
20216         if (!this.picker().isVisible()){
20217             if (e.keyCode == 27)   {// allow escape to hide and re-show picker
20218                 this.show();
20219             }
20220             return;
20221         }
20222         
20223         var dir;
20224         
20225         switch(e.keyCode){
20226             case 27: // escape
20227                 this.hide();
20228                 e.preventDefault();
20229                 break;
20230             case 37: // left
20231             case 39: // right
20232                 dir = e.keyCode == 37 ? -1 : 1;
20233                 
20234                 this.vIndex = this.vIndex + dir;
20235                 
20236                 if(this.vIndex < 0){
20237                     this.vIndex = 0;
20238                 }
20239                 
20240                 if(this.vIndex > 11){
20241                     this.vIndex = 11;
20242                 }
20243                 
20244                 if(isNaN(this.vIndex)){
20245                     this.vIndex = 0;
20246                 }
20247                 
20248                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20249                 
20250                 break;
20251             case 38: // up
20252             case 40: // down
20253                 
20254                 dir = e.keyCode == 38 ? -1 : 1;
20255                 
20256                 this.vIndex = this.vIndex + dir * 4;
20257                 
20258                 if(this.vIndex < 0){
20259                     this.vIndex = 0;
20260                 }
20261                 
20262                 if(this.vIndex > 11){
20263                     this.vIndex = 11;
20264                 }
20265                 
20266                 if(isNaN(this.vIndex)){
20267                     this.vIndex = 0;
20268                 }
20269                 
20270                 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20271                 break;
20272                 
20273             case 13: // enter
20274                 
20275                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20276                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20277                 }
20278                 
20279                 this.hide();
20280                 e.preventDefault();
20281                 break;
20282             case 9: // tab
20283                 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20284                     this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20285                 }
20286                 this.hide();
20287                 break;
20288             case 16: // shift
20289             case 17: // ctrl
20290             case 18: // alt
20291                 break;
20292             default :
20293                 this.hide();
20294                 
20295         }
20296     },
20297     
20298     remove: function() 
20299     {
20300         this.picker().remove();
20301     }
20302    
20303 });
20304
20305 Roo.apply(Roo.bootstrap.MonthField,  {
20306     
20307     content : {
20308         tag: 'tbody',
20309         cn: [
20310         {
20311             tag: 'tr',
20312             cn: [
20313             {
20314                 tag: 'td',
20315                 colspan: '7'
20316             }
20317             ]
20318         }
20319         ]
20320     },
20321     
20322     dates:{
20323         en: {
20324             months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20325             monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20326         }
20327     }
20328 });
20329
20330 Roo.apply(Roo.bootstrap.MonthField,  {
20331   
20332     template : {
20333         tag: 'div',
20334         cls: 'datepicker dropdown-menu roo-dynamic',
20335         cn: [
20336             {
20337                 tag: 'div',
20338                 cls: 'datepicker-months',
20339                 cn: [
20340                 {
20341                     tag: 'table',
20342                     cls: 'table-condensed',
20343                     cn:[
20344                         Roo.bootstrap.DateField.content
20345                     ]
20346                 }
20347                 ]
20348             }
20349         ]
20350     }
20351 });
20352
20353  
20354
20355  
20356  /*
20357  * - LGPL
20358  *
20359  * CheckBox
20360  * 
20361  */
20362
20363 /**
20364  * @class Roo.bootstrap.CheckBox
20365  * @extends Roo.bootstrap.Input
20366  * Bootstrap CheckBox class
20367  * 
20368  * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20369  * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20370  * @cfg {String} boxLabel The text that appears beside the checkbox
20371  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20372  * @cfg {Boolean} checked initnal the element
20373  * @cfg {Boolean} inline inline the element (default false)
20374  * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20375  * @cfg {String} tooltip label tooltip
20376  * 
20377  * @constructor
20378  * Create a new CheckBox
20379  * @param {Object} config The config object
20380  */
20381
20382 Roo.bootstrap.CheckBox = function(config){
20383     Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20384    
20385     this.addEvents({
20386         /**
20387         * @event check
20388         * Fires when the element is checked or unchecked.
20389         * @param {Roo.bootstrap.CheckBox} this This input
20390         * @param {Boolean} checked The new checked value
20391         */
20392        check : true,
20393        /**
20394         * @event click
20395         * Fires when the element is click.
20396         * @param {Roo.bootstrap.CheckBox} this This input
20397         */
20398        click : true
20399     });
20400     
20401 };
20402
20403 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input,  {
20404   
20405     inputType: 'checkbox',
20406     inputValue: 1,
20407     valueOff: 0,
20408     boxLabel: false,
20409     checked: false,
20410     weight : false,
20411     inline: false,
20412     tooltip : '',
20413     
20414     getAutoCreate : function()
20415     {
20416         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20417         
20418         var id = Roo.id();
20419         
20420         var cfg = {};
20421         
20422         cfg.cls = 'form-group ' + this.inputType; //input-group
20423         
20424         if(this.inline){
20425             cfg.cls += ' ' + this.inputType + '-inline';
20426         }
20427         
20428         var input =  {
20429             tag: 'input',
20430             id : id,
20431             type : this.inputType,
20432             value : this.inputValue,
20433             cls : 'roo-' + this.inputType, //'form-box',
20434             placeholder : this.placeholder || ''
20435             
20436         };
20437         
20438         if(this.inputType != 'radio'){
20439             var hidden =  {
20440                 tag: 'input',
20441                 type : 'hidden',
20442                 cls : 'roo-hidden-value',
20443                 value : this.checked ? this.inputValue : this.valueOff
20444             };
20445         }
20446         
20447             
20448         if (this.weight) { // Validity check?
20449             cfg.cls += " " + this.inputType + "-" + this.weight;
20450         }
20451         
20452         if (this.disabled) {
20453             input.disabled=true;
20454         }
20455         
20456         if(this.checked){
20457             input.checked = this.checked;
20458         }
20459         
20460         if (this.name) {
20461             
20462             input.name = this.name;
20463             
20464             if(this.inputType != 'radio'){
20465                 hidden.name = this.name;
20466                 input.name = '_hidden_' + this.name;
20467             }
20468         }
20469         
20470         if (this.size) {
20471             input.cls += ' input-' + this.size;
20472         }
20473         
20474         var settings=this;
20475         
20476         ['xs','sm','md','lg'].map(function(size){
20477             if (settings[size]) {
20478                 cfg.cls += ' col-' + size + '-' + settings[size];
20479             }
20480         });
20481         
20482         var inputblock = input;
20483          
20484         if (this.before || this.after) {
20485             
20486             inputblock = {
20487                 cls : 'input-group',
20488                 cn :  [] 
20489             };
20490             
20491             if (this.before) {
20492                 inputblock.cn.push({
20493                     tag :'span',
20494                     cls : 'input-group-addon',
20495                     html : this.before
20496                 });
20497             }
20498             
20499             inputblock.cn.push(input);
20500             
20501             if(this.inputType != 'radio'){
20502                 inputblock.cn.push(hidden);
20503             }
20504             
20505             if (this.after) {
20506                 inputblock.cn.push({
20507                     tag :'span',
20508                     cls : 'input-group-addon',
20509                     html : this.after
20510                 });
20511             }
20512             
20513         }
20514         
20515         if (align ==='left' && this.fieldLabel.length) {
20516 //                Roo.log("left and has label");
20517             cfg.cn = [
20518                 {
20519                     tag: 'label',
20520                     'for' :  id,
20521                     cls : 'control-label',
20522                     html : this.fieldLabel
20523                 },
20524                 {
20525                     cls : "", 
20526                     cn: [
20527                         inputblock
20528                     ]
20529                 }
20530             ];
20531             
20532             if(this.labelWidth > 12){
20533                 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20534             }
20535             
20536             if(this.labelWidth < 13 && this.labelmd == 0){
20537                 this.labelmd = this.labelWidth;
20538             }
20539             
20540             if(this.labellg > 0){
20541                 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20542                 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20543             }
20544             
20545             if(this.labelmd > 0){
20546                 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20547                 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20548             }
20549             
20550             if(this.labelsm > 0){
20551                 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20552                 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20553             }
20554             
20555             if(this.labelxs > 0){
20556                 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20557                 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20558             }
20559             
20560         } else if ( this.fieldLabel.length) {
20561 //                Roo.log(" label");
20562                 cfg.cn = [
20563                    
20564                     {
20565                         tag: this.boxLabel ? 'span' : 'label',
20566                         'for': id,
20567                         cls: 'control-label box-input-label',
20568                         //cls : 'input-group-addon',
20569                         html : this.fieldLabel
20570                     },
20571                     
20572                     inputblock
20573                     
20574                 ];
20575
20576         } else {
20577             
20578 //                Roo.log(" no label && no align");
20579                 cfg.cn = [  inputblock ] ;
20580                 
20581                 
20582         }
20583         
20584         if(this.boxLabel){
20585              var boxLabelCfg = {
20586                 tag: 'label',
20587                 //'for': id, // box label is handled by onclick - so no for...
20588                 cls: 'box-label',
20589                 html: this.boxLabel
20590             };
20591             
20592             if(this.tooltip){
20593                 boxLabelCfg.tooltip = this.tooltip;
20594             }
20595              
20596             cfg.cn.push(boxLabelCfg);
20597         }
20598         
20599         if(this.inputType != 'radio'){
20600             cfg.cn.push(hidden);
20601         }
20602         
20603         return cfg;
20604         
20605     },
20606     
20607     /**
20608      * return the real input element.
20609      */
20610     inputEl: function ()
20611     {
20612         return this.el.select('input.roo-' + this.inputType,true).first();
20613     },
20614     hiddenEl: function ()
20615     {
20616         return this.el.select('input.roo-hidden-value',true).first();
20617     },
20618     
20619     labelEl: function()
20620     {
20621         return this.el.select('label.control-label',true).first();
20622     },
20623     /* depricated... */
20624     
20625     label: function()
20626     {
20627         return this.labelEl();
20628     },
20629     
20630     boxLabelEl: function()
20631     {
20632         return this.el.select('label.box-label',true).first();
20633     },
20634     
20635     initEvents : function()
20636     {
20637 //        Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20638         
20639         this.inputEl().on('click', this.onClick,  this);
20640         
20641         if (this.boxLabel) { 
20642             this.el.select('label.box-label',true).first().on('click', this.onClick,  this);
20643         }
20644         
20645         this.startValue = this.getValue();
20646         
20647         if(this.groupId){
20648             Roo.bootstrap.CheckBox.register(this);
20649         }
20650     },
20651     
20652     onClick : function(e)
20653     {   
20654         if(this.fireEvent('click', this, e) !== false){
20655             this.setChecked(!this.checked);
20656         }
20657         
20658     },
20659     
20660     setChecked : function(state,suppressEvent)
20661     {
20662         this.startValue = this.getValue();
20663
20664         if(this.inputType == 'radio'){
20665             
20666             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20667                 e.dom.checked = false;
20668             });
20669             
20670             this.inputEl().dom.checked = true;
20671             
20672             this.inputEl().dom.value = this.inputValue;
20673             
20674             if(suppressEvent !== true){
20675                 this.fireEvent('check', this, true);
20676             }
20677             
20678             this.validate();
20679             
20680             return;
20681         }
20682         
20683         this.checked = state;
20684         
20685         this.inputEl().dom.checked = state;
20686         
20687         
20688         this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20689         
20690         if(suppressEvent !== true){
20691             this.fireEvent('check', this, state);
20692         }
20693         
20694         this.validate();
20695     },
20696     
20697     getValue : function()
20698     {
20699         if(this.inputType == 'radio'){
20700             return this.getGroupValue();
20701         }
20702         
20703         return this.hiddenEl().dom.value;
20704         
20705     },
20706     
20707     getGroupValue : function()
20708     {
20709         if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20710             return '';
20711         }
20712         
20713         return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20714     },
20715     
20716     setValue : function(v,suppressEvent)
20717     {
20718         if(this.inputType == 'radio'){
20719             this.setGroupValue(v, suppressEvent);
20720             return;
20721         }
20722         
20723         this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20724         
20725         this.validate();
20726     },
20727     
20728     setGroupValue : function(v, suppressEvent)
20729     {
20730         this.startValue = this.getValue();
20731         
20732         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20733             e.dom.checked = false;
20734             
20735             if(e.dom.value == v){
20736                 e.dom.checked = true;
20737             }
20738         });
20739         
20740         if(suppressEvent !== true){
20741             this.fireEvent('check', this, true);
20742         }
20743
20744         this.validate();
20745         
20746         return;
20747     },
20748     
20749     validate : function()
20750     {
20751         if(this.getVisibilityEl().hasClass('hidden')){
20752             return true;
20753         }
20754         
20755         if(
20756                 this.disabled || 
20757                 (this.inputType == 'radio' && this.validateRadio()) ||
20758                 (this.inputType == 'checkbox' && this.validateCheckbox())
20759         ){
20760             this.markValid();
20761             return true;
20762         }
20763         
20764         this.markInvalid();
20765         return false;
20766     },
20767     
20768     validateRadio : function()
20769     {
20770         if(this.getVisibilityEl().hasClass('hidden')){
20771             return true;
20772         }
20773         
20774         if(this.allowBlank){
20775             return true;
20776         }
20777         
20778         var valid = false;
20779         
20780         Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20781             if(!e.dom.checked){
20782                 return;
20783             }
20784             
20785             valid = true;
20786             
20787             return false;
20788         });
20789         
20790         return valid;
20791     },
20792     
20793     validateCheckbox : function()
20794     {
20795         if(!this.groupId){
20796             return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
20797             //return (this.getValue() == this.inputValue) ? true : false;
20798         }
20799         
20800         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20801         
20802         if(!group){
20803             return false;
20804         }
20805         
20806         var r = false;
20807         
20808         for(var i in group){
20809             if(group[i].el.isVisible(true)){
20810                 r = false;
20811                 break;
20812             }
20813             
20814             r = true;
20815         }
20816         
20817         for(var i in group){
20818             if(r){
20819                 break;
20820             }
20821             
20822             r = (group[i].getValue() == group[i].inputValue) ? true : false;
20823         }
20824         
20825         return r;
20826     },
20827     
20828     /**
20829      * Mark this field as valid
20830      */
20831     markValid : function()
20832     {
20833         var _this = this;
20834         
20835         this.fireEvent('valid', this);
20836         
20837         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20838         
20839         if(this.groupId){
20840             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20841         }
20842         
20843         if(label){
20844             label.markValid();
20845         }
20846
20847         if(this.inputType == 'radio'){
20848             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20849                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20850                 e.findParent('.form-group', false, true).addClass(_this.validClass);
20851             });
20852             
20853             return;
20854         }
20855
20856         if(!this.groupId){
20857             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20858             this.el.findParent('.form-group', false, true).addClass(this.validClass);
20859             return;
20860         }
20861         
20862         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20863         
20864         if(!group){
20865             return;
20866         }
20867         
20868         for(var i in group){
20869             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20870             group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
20871         }
20872     },
20873     
20874      /**
20875      * Mark this field as invalid
20876      * @param {String} msg The validation message
20877      */
20878     markInvalid : function(msg)
20879     {
20880         if(this.allowBlank){
20881             return;
20882         }
20883         
20884         var _this = this;
20885         
20886         this.fireEvent('invalid', this, msg);
20887         
20888         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20889         
20890         if(this.groupId){
20891             label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
20892         }
20893         
20894         if(label){
20895             label.markInvalid();
20896         }
20897             
20898         if(this.inputType == 'radio'){
20899             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20900                 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
20901                 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
20902             });
20903             
20904             return;
20905         }
20906         
20907         if(!this.groupId){
20908             this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20909             this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
20910             return;
20911         }
20912         
20913         var group = Roo.bootstrap.CheckBox.get(this.groupId);
20914         
20915         if(!group){
20916             return;
20917         }
20918         
20919         for(var i in group){
20920             group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20921             group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
20922         }
20923         
20924     },
20925     
20926     clearInvalid : function()
20927     {
20928         Roo.bootstrap.Input.prototype.clearInvalid.call(this);
20929         
20930         // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
20931         
20932         var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
20933         
20934         if (label && label.iconEl) {
20935             label.iconEl.removeClass(label.validClass);
20936             label.iconEl.removeClass(label.invalidClass);
20937         }
20938     },
20939     
20940     disable : function()
20941     {
20942         if(this.inputType != 'radio'){
20943             Roo.bootstrap.CheckBox.superclass.disable.call(this);
20944             return;
20945         }
20946         
20947         var _this = this;
20948         
20949         if(this.rendered){
20950             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20951                 _this.getActionEl().addClass(this.disabledClass);
20952                 e.dom.disabled = true;
20953             });
20954         }
20955         
20956         this.disabled = true;
20957         this.fireEvent("disable", this);
20958         return this;
20959     },
20960
20961     enable : function()
20962     {
20963         if(this.inputType != 'radio'){
20964             Roo.bootstrap.CheckBox.superclass.enable.call(this);
20965             return;
20966         }
20967         
20968         var _this = this;
20969         
20970         if(this.rendered){
20971             Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20972                 _this.getActionEl().removeClass(this.disabledClass);
20973                 e.dom.disabled = false;
20974             });
20975         }
20976         
20977         this.disabled = false;
20978         this.fireEvent("enable", this);
20979         return this;
20980     },
20981     
20982     setBoxLabel : function(v)
20983     {
20984         this.boxLabel = v;
20985         
20986         if(this.rendered){
20987             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
20988         }
20989     }
20990
20991 });
20992
20993 Roo.apply(Roo.bootstrap.CheckBox, {
20994     
20995     groups: {},
20996     
20997      /**
20998     * register a CheckBox Group
20999     * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21000     */
21001     register : function(checkbox)
21002     {
21003         if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21004             this.groups[checkbox.groupId] = {};
21005         }
21006         
21007         if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21008             return;
21009         }
21010         
21011         this.groups[checkbox.groupId][checkbox.name] = checkbox;
21012         
21013     },
21014     /**
21015     * fetch a CheckBox Group based on the group ID
21016     * @param {string} the group ID
21017     * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21018     */
21019     get: function(groupId) {
21020         if (typeof(this.groups[groupId]) == 'undefined') {
21021             return false;
21022         }
21023         
21024         return this.groups[groupId] ;
21025     }
21026     
21027     
21028 });
21029 /*
21030  * - LGPL
21031  *
21032  * RadioItem
21033  * 
21034  */
21035
21036 /**
21037  * @class Roo.bootstrap.Radio
21038  * @extends Roo.bootstrap.Component
21039  * Bootstrap Radio class
21040  * @cfg {String} boxLabel - the label associated
21041  * @cfg {String} value - the value of radio
21042  * 
21043  * @constructor
21044  * Create a new Radio
21045  * @param {Object} config The config object
21046  */
21047 Roo.bootstrap.Radio = function(config){
21048     Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21049     
21050 };
21051
21052 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21053     
21054     boxLabel : '',
21055     
21056     value : '',
21057     
21058     getAutoCreate : function()
21059     {
21060         var cfg = {
21061             tag : 'div',
21062             cls : 'form-group radio',
21063             cn : [
21064                 {
21065                     tag : 'label',
21066                     cls : 'box-label',
21067                     html : this.boxLabel
21068                 }
21069             ]
21070         };
21071         
21072         return cfg;
21073     },
21074     
21075     initEvents : function() 
21076     {
21077         this.parent().register(this);
21078         
21079         this.el.on('click', this.onClick, this);
21080         
21081     },
21082     
21083     onClick : function(e)
21084     {
21085         if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21086             this.setChecked(true);
21087         }
21088     },
21089     
21090     setChecked : function(state, suppressEvent)
21091     {
21092         this.parent().setValue(this.value, suppressEvent);
21093         
21094     },
21095     
21096     setBoxLabel : function(v)
21097     {
21098         this.boxLabel = v;
21099         
21100         if(this.rendered){
21101             this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21102         }
21103     }
21104     
21105 });
21106  
21107
21108  /*
21109  * - LGPL
21110  *
21111  * Input
21112  * 
21113  */
21114
21115 /**
21116  * @class Roo.bootstrap.SecurePass
21117  * @extends Roo.bootstrap.Input
21118  * Bootstrap SecurePass class
21119  *
21120  * 
21121  * @constructor
21122  * Create a new SecurePass
21123  * @param {Object} config The config object
21124  */
21125  
21126 Roo.bootstrap.SecurePass = function (config) {
21127     // these go here, so the translation tool can replace them..
21128     this.errors = {
21129         PwdEmpty: "Please type a password, and then retype it to confirm.",
21130         PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21131         PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21132         PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21133         IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21134         FNInPwd: "Your password can't contain your first name. Please type a different password.",
21135         LNInPwd: "Your password can't contain your last name. Please type a different password.",
21136         TooWeak: "Your password is Too Weak."
21137     },
21138     this.meterLabel = "Password strength:";
21139     this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21140     this.meterClass = [
21141         "roo-password-meter-tooweak", 
21142         "roo-password-meter-weak", 
21143         "roo-password-meter-medium", 
21144         "roo-password-meter-strong", 
21145         "roo-password-meter-grey"
21146     ];
21147     
21148     this.errors = {};
21149     
21150     Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21151 }
21152
21153 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21154     /**
21155      * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21156      * {
21157      *  PwdEmpty: "Please type a password, and then retype it to confirm.",
21158      *  PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21159      *  PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21160      *  PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21161      *  IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21162      *  FNInPwd: "Your password can't contain your first name. Please type a different password.",
21163      *  LNInPwd: "Your password can't contain your last name. Please type a different password."
21164      * })
21165      */
21166     // private
21167     
21168     meterWidth: 300,
21169     errorMsg :'',    
21170     errors: false,
21171     imageRoot: '/',
21172     /**
21173      * @cfg {String/Object} Label for the strength meter (defaults to
21174      * 'Password strength:')
21175      */
21176     // private
21177     meterLabel: '',
21178     /**
21179      * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21180      * ['Weak', 'Medium', 'Strong'])
21181      */
21182     // private    
21183     pwdStrengths: false,    
21184     // private
21185     strength: 0,
21186     // private
21187     _lastPwd: null,
21188     // private
21189     kCapitalLetter: 0,
21190     kSmallLetter: 1,
21191     kDigit: 2,
21192     kPunctuation: 3,
21193     
21194     insecure: false,
21195     // private
21196     initEvents: function ()
21197     {
21198         Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21199
21200         if (this.el.is('input[type=password]') && Roo.isSafari) {
21201             this.el.on('keydown', this.SafariOnKeyDown, this);
21202         }
21203
21204         this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21205     },
21206     // private
21207     onRender: function (ct, position)
21208     {
21209         Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21210         this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21211         this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21212
21213         this.trigger.createChild({
21214                    cn: [
21215                     {
21216                     //id: 'PwdMeter',
21217                     tag: 'div',
21218                     cls: 'roo-password-meter-grey col-xs-12',
21219                     style: {
21220                         //width: 0,
21221                         //width: this.meterWidth + 'px'                                                
21222                         }
21223                     },
21224                     {                            
21225                          cls: 'roo-password-meter-text'                          
21226                     }
21227                 ]            
21228         });
21229
21230          
21231         if (this.hideTrigger) {
21232             this.trigger.setDisplayed(false);
21233         }
21234         this.setSize(this.width || '', this.height || '');
21235     },
21236     // private
21237     onDestroy: function ()
21238     {
21239         if (this.trigger) {
21240             this.trigger.removeAllListeners();
21241             this.trigger.remove();
21242         }
21243         if (this.wrap) {
21244             this.wrap.remove();
21245         }
21246         Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21247     },
21248     // private
21249     checkStrength: function ()
21250     {
21251         var pwd = this.inputEl().getValue();
21252         if (pwd == this._lastPwd) {
21253             return;
21254         }
21255
21256         var strength;
21257         if (this.ClientSideStrongPassword(pwd)) {
21258             strength = 3;
21259         } else if (this.ClientSideMediumPassword(pwd)) {
21260             strength = 2;
21261         } else if (this.ClientSideWeakPassword(pwd)) {
21262             strength = 1;
21263         } else {
21264             strength = 0;
21265         }
21266         
21267         Roo.log('strength1: ' + strength);
21268         
21269         //var pm = this.trigger.child('div/div/div').dom;
21270         var pm = this.trigger.child('div/div');
21271         pm.removeClass(this.meterClass);
21272         pm.addClass(this.meterClass[strength]);
21273                 
21274         
21275         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21276                 
21277         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21278         
21279         this._lastPwd = pwd;
21280     },
21281     reset: function ()
21282     {
21283         Roo.bootstrap.SecurePass.superclass.reset.call(this);
21284         
21285         this._lastPwd = '';
21286         
21287         var pm = this.trigger.child('div/div');
21288         pm.removeClass(this.meterClass);
21289         pm.addClass('roo-password-meter-grey');        
21290         
21291         
21292         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21293         
21294         pt.innerHTML = '';
21295         this.inputEl().dom.type='password';
21296     },
21297     // private
21298     validateValue: function (value)
21299     {
21300         
21301         if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21302             return false;
21303         }
21304         if (value.length == 0) {
21305             if (this.allowBlank) {
21306                 this.clearInvalid();
21307                 return true;
21308             }
21309
21310             this.markInvalid(this.errors.PwdEmpty);
21311             this.errorMsg = this.errors.PwdEmpty;
21312             return false;
21313         }
21314         
21315         if(this.insecure){
21316             return true;
21317         }
21318         
21319         if ('[\x21-\x7e]*'.match(value)) {
21320             this.markInvalid(this.errors.PwdBadChar);
21321             this.errorMsg = this.errors.PwdBadChar;
21322             return false;
21323         }
21324         if (value.length < 6) {
21325             this.markInvalid(this.errors.PwdShort);
21326             this.errorMsg = this.errors.PwdShort;
21327             return false;
21328         }
21329         if (value.length > 16) {
21330             this.markInvalid(this.errors.PwdLong);
21331             this.errorMsg = this.errors.PwdLong;
21332             return false;
21333         }
21334         var strength;
21335         if (this.ClientSideStrongPassword(value)) {
21336             strength = 3;
21337         } else if (this.ClientSideMediumPassword(value)) {
21338             strength = 2;
21339         } else if (this.ClientSideWeakPassword(value)) {
21340             strength = 1;
21341         } else {
21342             strength = 0;
21343         }
21344
21345         
21346         if (strength < 2) {
21347             //this.markInvalid(this.errors.TooWeak);
21348             this.errorMsg = this.errors.TooWeak;
21349             //return false;
21350         }
21351         
21352         
21353         console.log('strength2: ' + strength);
21354         
21355         //var pm = this.trigger.child('div/div/div').dom;
21356         
21357         var pm = this.trigger.child('div/div');
21358         pm.removeClass(this.meterClass);
21359         pm.addClass(this.meterClass[strength]);
21360                 
21361         var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;        
21362                 
21363         pt.innerHTML = this.meterLabel + '&nbsp;' + this.pwdStrengths[strength];
21364         
21365         this.errorMsg = ''; 
21366         return true;
21367     },
21368     // private
21369     CharacterSetChecks: function (type)
21370     {
21371         this.type = type;
21372         this.fResult = false;
21373     },
21374     // private
21375     isctype: function (character, type)
21376     {
21377         switch (type) {  
21378             case this.kCapitalLetter:
21379                 if (character >= 'A' && character <= 'Z') {
21380                     return true;
21381                 }
21382                 break;
21383             
21384             case this.kSmallLetter:
21385                 if (character >= 'a' && character <= 'z') {
21386                     return true;
21387                 }
21388                 break;
21389             
21390             case this.kDigit:
21391                 if (character >= '0' && character <= '9') {
21392                     return true;
21393                 }
21394                 break;
21395             
21396             case this.kPunctuation:
21397                 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21398                     return true;
21399                 }
21400                 break;
21401             
21402             default:
21403                 return false;
21404         }
21405
21406     },
21407     // private
21408     IsLongEnough: function (pwd, size)
21409     {
21410         return !(pwd == null || isNaN(size) || pwd.length < size);
21411     },
21412     // private
21413     SpansEnoughCharacterSets: function (word, nb)
21414     {
21415         if (!this.IsLongEnough(word, nb))
21416         {
21417             return false;
21418         }
21419
21420         var characterSetChecks = new Array(
21421             new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21422             new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21423         );
21424         
21425         for (var index = 0; index < word.length; ++index) {
21426             for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21427                 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21428                     characterSetChecks[nCharSet].fResult = true;
21429                     break;
21430                 }
21431             }
21432         }
21433
21434         var nCharSets = 0;
21435         for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21436             if (characterSetChecks[nCharSet].fResult) {
21437                 ++nCharSets;
21438             }
21439         }
21440
21441         if (nCharSets < nb) {
21442             return false;
21443         }
21444         return true;
21445     },
21446     // private
21447     ClientSideStrongPassword: function (pwd)
21448     {
21449         return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21450     },
21451     // private
21452     ClientSideMediumPassword: function (pwd)
21453     {
21454         return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21455     },
21456     // private
21457     ClientSideWeakPassword: function (pwd)
21458     {
21459         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21460     }
21461           
21462 })//<script type="text/javascript">
21463
21464 /*
21465  * Based  Ext JS Library 1.1.1
21466  * Copyright(c) 2006-2007, Ext JS, LLC.
21467  * LGPL
21468  *
21469  */
21470  
21471 /**
21472  * @class Roo.HtmlEditorCore
21473  * @extends Roo.Component
21474  * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21475  *
21476  * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21477  */
21478
21479 Roo.HtmlEditorCore = function(config){
21480     
21481     
21482     Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21483     
21484     
21485     this.addEvents({
21486         /**
21487          * @event initialize
21488          * Fires when the editor is fully initialized (including the iframe)
21489          * @param {Roo.HtmlEditorCore} this
21490          */
21491         initialize: true,
21492         /**
21493          * @event activate
21494          * Fires when the editor is first receives the focus. Any insertion must wait
21495          * until after this event.
21496          * @param {Roo.HtmlEditorCore} this
21497          */
21498         activate: true,
21499          /**
21500          * @event beforesync
21501          * Fires before the textarea is updated with content from the editor iframe. Return false
21502          * to cancel the sync.
21503          * @param {Roo.HtmlEditorCore} this
21504          * @param {String} html
21505          */
21506         beforesync: true,
21507          /**
21508          * @event beforepush
21509          * Fires before the iframe editor is updated with content from the textarea. Return false
21510          * to cancel the push.
21511          * @param {Roo.HtmlEditorCore} this
21512          * @param {String} html
21513          */
21514         beforepush: true,
21515          /**
21516          * @event sync
21517          * Fires when the textarea is updated with content from the editor iframe.
21518          * @param {Roo.HtmlEditorCore} this
21519          * @param {String} html
21520          */
21521         sync: true,
21522          /**
21523          * @event push
21524          * Fires when the iframe editor is updated with content from the textarea.
21525          * @param {Roo.HtmlEditorCore} this
21526          * @param {String} html
21527          */
21528         push: true,
21529         
21530         /**
21531          * @event editorevent
21532          * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21533          * @param {Roo.HtmlEditorCore} this
21534          */
21535         editorevent: true
21536         
21537     });
21538     
21539     // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21540     
21541     // defaults : white / black...
21542     this.applyBlacklists();
21543     
21544     
21545     
21546 };
21547
21548
21549 Roo.extend(Roo.HtmlEditorCore, Roo.Component,  {
21550
21551
21552      /**
21553      * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field 
21554      */
21555     
21556     owner : false,
21557     
21558      /**
21559      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
21560      *                        Roo.resizable.
21561      */
21562     resizable : false,
21563      /**
21564      * @cfg {Number} height (in pixels)
21565      */   
21566     height: 300,
21567    /**
21568      * @cfg {Number} width (in pixels)
21569      */   
21570     width: 500,
21571     
21572     /**
21573      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21574      * 
21575      */
21576     stylesheets: false,
21577     
21578     // id of frame..
21579     frameId: false,
21580     
21581     // private properties
21582     validationEvent : false,
21583     deferHeight: true,
21584     initialized : false,
21585     activated : false,
21586     sourceEditMode : false,
21587     onFocus : Roo.emptyFn,
21588     iframePad:3,
21589     hideMode:'offsets',
21590     
21591     clearUp: true,
21592     
21593     // blacklist + whitelisted elements..
21594     black: false,
21595     white: false,
21596      
21597     bodyCls : '',
21598
21599     /**
21600      * Protected method that will not generally be called directly. It
21601      * is called when the editor initializes the iframe with HTML contents. Override this method if you
21602      * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21603      */
21604     getDocMarkup : function(){
21605         // body styles..
21606         var st = '';
21607         
21608         // inherit styels from page...?? 
21609         if (this.stylesheets === false) {
21610             
21611             Roo.get(document.head).select('style').each(function(node) {
21612                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21613             });
21614             
21615             Roo.get(document.head).select('link').each(function(node) { 
21616                 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21617             });
21618             
21619         } else if (!this.stylesheets.length) {
21620                 // simple..
21621                 st = '<style type="text/css">' +
21622                     'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21623                    '</style>';
21624         } else { 
21625             st = '<style type="text/css">' +
21626                     this.stylesheets +
21627                 '</style>';
21628         }
21629         
21630         st +=  '<style type="text/css">' +
21631             'IMG { cursor: pointer } ' +
21632         '</style>';
21633
21634         var cls = 'roo-htmleditor-body';
21635         
21636         if(this.bodyCls.length){
21637             cls += ' ' + this.bodyCls;
21638         }
21639         
21640         return '<html><head>' + st  +
21641             //<style type="text/css">' +
21642             //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21643             //'</style>' +
21644             ' </head><body class="' +  cls + '"></body></html>';
21645     },
21646
21647     // private
21648     onRender : function(ct, position)
21649     {
21650         var _t = this;
21651         //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21652         this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21653         
21654         
21655         this.el.dom.style.border = '0 none';
21656         this.el.dom.setAttribute('tabIndex', -1);
21657         this.el.addClass('x-hidden hide');
21658         
21659         
21660         
21661         if(Roo.isIE){ // fix IE 1px bogus margin
21662             this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21663         }
21664        
21665         
21666         this.frameId = Roo.id();
21667         
21668          
21669         
21670         var iframe = this.owner.wrap.createChild({
21671             tag: 'iframe',
21672             cls: 'form-control', // bootstrap..
21673             id: this.frameId,
21674             name: this.frameId,
21675             frameBorder : 'no',
21676             'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL  :  "javascript:false"
21677         }, this.el
21678         );
21679         
21680         
21681         this.iframe = iframe.dom;
21682
21683          this.assignDocWin();
21684         
21685         this.doc.designMode = 'on';
21686        
21687         this.doc.open();
21688         this.doc.write(this.getDocMarkup());
21689         this.doc.close();
21690
21691         
21692         var task = { // must defer to wait for browser to be ready
21693             run : function(){
21694                 //console.log("run task?" + this.doc.readyState);
21695                 this.assignDocWin();
21696                 if(this.doc.body || this.doc.readyState == 'complete'){
21697                     try {
21698                         this.doc.designMode="on";
21699                     } catch (e) {
21700                         return;
21701                     }
21702                     Roo.TaskMgr.stop(task);
21703                     this.initEditor.defer(10, this);
21704                 }
21705             },
21706             interval : 10,
21707             duration: 10000,
21708             scope: this
21709         };
21710         Roo.TaskMgr.start(task);
21711
21712     },
21713
21714     // private
21715     onResize : function(w, h)
21716     {
21717          Roo.log('resize: ' +w + ',' + h );
21718         //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21719         if(!this.iframe){
21720             return;
21721         }
21722         if(typeof w == 'number'){
21723             
21724             this.iframe.style.width = w + 'px';
21725         }
21726         if(typeof h == 'number'){
21727             
21728             this.iframe.style.height = h + 'px';
21729             if(this.doc){
21730                 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
21731             }
21732         }
21733         
21734     },
21735
21736     /**
21737      * Toggles the editor between standard and source edit mode.
21738      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
21739      */
21740     toggleSourceEdit : function(sourceEditMode){
21741         
21742         this.sourceEditMode = sourceEditMode === true;
21743         
21744         if(this.sourceEditMode){
21745  
21746             Roo.get(this.iframe).addClass(['x-hidden','hide']);     //FIXME - what's the BS styles for these
21747             
21748         }else{
21749             Roo.get(this.iframe).removeClass(['x-hidden','hide']);
21750             //this.iframe.className = '';
21751             this.deferFocus();
21752         }
21753         //this.setSize(this.owner.wrap.getSize());
21754         //this.fireEvent('editmodechange', this, this.sourceEditMode);
21755     },
21756
21757     
21758   
21759
21760     /**
21761      * Protected method that will not generally be called directly. If you need/want
21762      * custom HTML cleanup, this is the method you should override.
21763      * @param {String} html The HTML to be cleaned
21764      * return {String} The cleaned HTML
21765      */
21766     cleanHtml : function(html){
21767         html = String(html);
21768         if(html.length > 5){
21769             if(Roo.isSafari){ // strip safari nonsense
21770                 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
21771             }
21772         }
21773         if(html == '&nbsp;'){
21774             html = '';
21775         }
21776         return html;
21777     },
21778
21779     /**
21780      * HTML Editor -> Textarea
21781      * Protected method that will not generally be called directly. Syncs the contents
21782      * of the editor iframe with the textarea.
21783      */
21784     syncValue : function(){
21785         if(this.initialized){
21786             var bd = (this.doc.body || this.doc.documentElement);
21787             //this.cleanUpPaste(); -- this is done else where and causes havoc..
21788             var html = bd.innerHTML;
21789             if(Roo.isSafari){
21790                 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
21791                 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
21792                 if(m && m[1]){
21793                     html = '<div style="'+m[0]+'">' + html + '</div>';
21794                 }
21795             }
21796             html = this.cleanHtml(html);
21797             // fix up the special chars.. normaly like back quotes in word...
21798             // however we do not want to do this with chinese..
21799             html = html.replace(/([\x80-\uffff])/g, function (a, b) {
21800                 var cc = b.charCodeAt();
21801                 if (
21802                     (cc >= 0x4E00 && cc < 0xA000 ) ||
21803                     (cc >= 0x3400 && cc < 0x4E00 ) ||
21804                     (cc >= 0xf900 && cc < 0xfb00 )
21805                 ) {
21806                         return b;
21807                 }
21808                 return "&#"+cc+";" 
21809             });
21810             if(this.owner.fireEvent('beforesync', this, html) !== false){
21811                 this.el.dom.value = html;
21812                 this.owner.fireEvent('sync', this, html);
21813             }
21814         }
21815     },
21816
21817     /**
21818      * Protected method that will not generally be called directly. Pushes the value of the textarea
21819      * into the iframe editor.
21820      */
21821     pushValue : function(){
21822         if(this.initialized){
21823             var v = this.el.dom.value.trim();
21824             
21825 //            if(v.length < 1){
21826 //                v = '&#160;';
21827 //            }
21828             
21829             if(this.owner.fireEvent('beforepush', this, v) !== false){
21830                 var d = (this.doc.body || this.doc.documentElement);
21831                 d.innerHTML = v;
21832                 this.cleanUpPaste();
21833                 this.el.dom.value = d.innerHTML;
21834                 this.owner.fireEvent('push', this, v);
21835             }
21836         }
21837     },
21838
21839     // private
21840     deferFocus : function(){
21841         this.focus.defer(10, this);
21842     },
21843
21844     // doc'ed in Field
21845     focus : function(){
21846         if(this.win && !this.sourceEditMode){
21847             this.win.focus();
21848         }else{
21849             this.el.focus();
21850         }
21851     },
21852     
21853     assignDocWin: function()
21854     {
21855         var iframe = this.iframe;
21856         
21857          if(Roo.isIE){
21858             this.doc = iframe.contentWindow.document;
21859             this.win = iframe.contentWindow;
21860         } else {
21861 //            if (!Roo.get(this.frameId)) {
21862 //                return;
21863 //            }
21864 //            this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21865 //            this.win = Roo.get(this.frameId).dom.contentWindow;
21866             
21867             if (!Roo.get(this.frameId) && !iframe.contentDocument) {
21868                 return;
21869             }
21870             
21871             this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
21872             this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
21873         }
21874     },
21875     
21876     // private
21877     initEditor : function(){
21878         //console.log("INIT EDITOR");
21879         this.assignDocWin();
21880         
21881         
21882         
21883         this.doc.designMode="on";
21884         this.doc.open();
21885         this.doc.write(this.getDocMarkup());
21886         this.doc.close();
21887         
21888         var dbody = (this.doc.body || this.doc.documentElement);
21889         //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
21890         // this copies styles from the containing element into thsi one..
21891         // not sure why we need all of this..
21892         //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
21893         
21894         //var ss = this.el.getStyles( 'background-image', 'background-repeat');
21895         //ss['background-attachment'] = 'fixed'; // w3c
21896         dbody.bgProperties = 'fixed'; // ie
21897         //Roo.DomHelper.applyStyles(dbody, ss);
21898         Roo.EventManager.on(this.doc, {
21899             //'mousedown': this.onEditorEvent,
21900             'mouseup': this.onEditorEvent,
21901             'dblclick': this.onEditorEvent,
21902             'click': this.onEditorEvent,
21903             'keyup': this.onEditorEvent,
21904             buffer:100,
21905             scope: this
21906         });
21907         if(Roo.isGecko){
21908             Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
21909         }
21910         if(Roo.isIE || Roo.isSafari || Roo.isOpera){
21911             Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
21912         }
21913         this.initialized = true;
21914
21915         this.owner.fireEvent('initialize', this);
21916         this.pushValue();
21917     },
21918
21919     // private
21920     onDestroy : function(){
21921         
21922         
21923         
21924         if(this.rendered){
21925             
21926             //for (var i =0; i < this.toolbars.length;i++) {
21927             //    // fixme - ask toolbars for heights?
21928             //    this.toolbars[i].onDestroy();
21929            // }
21930             
21931             //this.wrap.dom.innerHTML = '';
21932             //this.wrap.remove();
21933         }
21934     },
21935
21936     // private
21937     onFirstFocus : function(){
21938         
21939         this.assignDocWin();
21940         
21941         
21942         this.activated = true;
21943          
21944     
21945         if(Roo.isGecko){ // prevent silly gecko errors
21946             this.win.focus();
21947             var s = this.win.getSelection();
21948             if(!s.focusNode || s.focusNode.nodeType != 3){
21949                 var r = s.getRangeAt(0);
21950                 r.selectNodeContents((this.doc.body || this.doc.documentElement));
21951                 r.collapse(true);
21952                 this.deferFocus();
21953             }
21954             try{
21955                 this.execCmd('useCSS', true);
21956                 this.execCmd('styleWithCSS', false);
21957             }catch(e){}
21958         }
21959         this.owner.fireEvent('activate', this);
21960     },
21961
21962     // private
21963     adjustFont: function(btn){
21964         var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
21965         //if(Roo.isSafari){ // safari
21966         //    adjust *= 2;
21967        // }
21968         var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
21969         if(Roo.isSafari){ // safari
21970             var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
21971             v =  (v < 10) ? 10 : v;
21972             v =  (v > 48) ? 48 : v;
21973             v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
21974             
21975         }
21976         
21977         
21978         v = Math.max(1, v+adjust);
21979         
21980         this.execCmd('FontSize', v  );
21981     },
21982
21983     onEditorEvent : function(e)
21984     {
21985         this.owner.fireEvent('editorevent', this, e);
21986       //  this.updateToolbar();
21987         this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
21988     },
21989
21990     insertTag : function(tg)
21991     {
21992         // could be a bit smarter... -> wrap the current selected tRoo..
21993         if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
21994             
21995             range = this.createRange(this.getSelection());
21996             var wrappingNode = this.doc.createElement(tg.toLowerCase());
21997             wrappingNode.appendChild(range.extractContents());
21998             range.insertNode(wrappingNode);
21999
22000             return;
22001             
22002             
22003             
22004         }
22005         this.execCmd("formatblock",   tg);
22006         
22007     },
22008     
22009     insertText : function(txt)
22010     {
22011         
22012         
22013         var range = this.createRange();
22014         range.deleteContents();
22015                //alert(Sender.getAttribute('label'));
22016                
22017         range.insertNode(this.doc.createTextNode(txt));
22018     } ,
22019     
22020      
22021
22022     /**
22023      * Executes a Midas editor command on the editor document and performs necessary focus and
22024      * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22025      * @param {String} cmd The Midas command
22026      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22027      */
22028     relayCmd : function(cmd, value){
22029         this.win.focus();
22030         this.execCmd(cmd, value);
22031         this.owner.fireEvent('editorevent', this);
22032         //this.updateToolbar();
22033         this.owner.deferFocus();
22034     },
22035
22036     /**
22037      * Executes a Midas editor command directly on the editor document.
22038      * For visual commands, you should use {@link #relayCmd} instead.
22039      * <b>This should only be called after the editor is initialized.</b>
22040      * @param {String} cmd The Midas command
22041      * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22042      */
22043     execCmd : function(cmd, value){
22044         this.doc.execCommand(cmd, false, value === undefined ? null : value);
22045         this.syncValue();
22046     },
22047  
22048  
22049    
22050     /**
22051      * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22052      * to insert tRoo.
22053      * @param {String} text | dom node.. 
22054      */
22055     insertAtCursor : function(text)
22056     {
22057         
22058         if(!this.activated){
22059             return;
22060         }
22061         /*
22062         if(Roo.isIE){
22063             this.win.focus();
22064             var r = this.doc.selection.createRange();
22065             if(r){
22066                 r.collapse(true);
22067                 r.pasteHTML(text);
22068                 this.syncValue();
22069                 this.deferFocus();
22070             
22071             }
22072             return;
22073         }
22074         */
22075         if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22076             this.win.focus();
22077             
22078             
22079             // from jquery ui (MIT licenced)
22080             var range, node;
22081             var win = this.win;
22082             
22083             if (win.getSelection && win.getSelection().getRangeAt) {
22084                 range = win.getSelection().getRangeAt(0);
22085                 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22086                 range.insertNode(node);
22087             } else if (win.document.selection && win.document.selection.createRange) {
22088                 // no firefox support
22089                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22090                 win.document.selection.createRange().pasteHTML(txt);
22091             } else {
22092                 // no firefox support
22093                 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22094                 this.execCmd('InsertHTML', txt);
22095             } 
22096             
22097             this.syncValue();
22098             
22099             this.deferFocus();
22100         }
22101     },
22102  // private
22103     mozKeyPress : function(e){
22104         if(e.ctrlKey){
22105             var c = e.getCharCode(), cmd;
22106           
22107             if(c > 0){
22108                 c = String.fromCharCode(c).toLowerCase();
22109                 switch(c){
22110                     case 'b':
22111                         cmd = 'bold';
22112                         break;
22113                     case 'i':
22114                         cmd = 'italic';
22115                         break;
22116                     
22117                     case 'u':
22118                         cmd = 'underline';
22119                         break;
22120                     
22121                     case 'v':
22122                         this.cleanUpPaste.defer(100, this);
22123                         return;
22124                         
22125                 }
22126                 if(cmd){
22127                     this.win.focus();
22128                     this.execCmd(cmd);
22129                     this.deferFocus();
22130                     e.preventDefault();
22131                 }
22132                 
22133             }
22134         }
22135     },
22136
22137     // private
22138     fixKeys : function(){ // load time branching for fastest keydown performance
22139         if(Roo.isIE){
22140             return function(e){
22141                 var k = e.getKey(), r;
22142                 if(k == e.TAB){
22143                     e.stopEvent();
22144                     r = this.doc.selection.createRange();
22145                     if(r){
22146                         r.collapse(true);
22147                         r.pasteHTML('&#160;&#160;&#160;&#160;');
22148                         this.deferFocus();
22149                     }
22150                     return;
22151                 }
22152                 
22153                 if(k == e.ENTER){
22154                     r = this.doc.selection.createRange();
22155                     if(r){
22156                         var target = r.parentElement();
22157                         if(!target || target.tagName.toLowerCase() != 'li'){
22158                             e.stopEvent();
22159                             r.pasteHTML('<br />');
22160                             r.collapse(false);
22161                             r.select();
22162                         }
22163                     }
22164                 }
22165                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22166                     this.cleanUpPaste.defer(100, this);
22167                     return;
22168                 }
22169                 
22170                 
22171             };
22172         }else if(Roo.isOpera){
22173             return function(e){
22174                 var k = e.getKey();
22175                 if(k == e.TAB){
22176                     e.stopEvent();
22177                     this.win.focus();
22178                     this.execCmd('InsertHTML','&#160;&#160;&#160;&#160;');
22179                     this.deferFocus();
22180                 }
22181                 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22182                     this.cleanUpPaste.defer(100, this);
22183                     return;
22184                 }
22185                 
22186             };
22187         }else if(Roo.isSafari){
22188             return function(e){
22189                 var k = e.getKey();
22190                 
22191                 if(k == e.TAB){
22192                     e.stopEvent();
22193                     this.execCmd('InsertText','\t');
22194                     this.deferFocus();
22195                     return;
22196                 }
22197                if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22198                     this.cleanUpPaste.defer(100, this);
22199                     return;
22200                 }
22201                 
22202              };
22203         }
22204     }(),
22205     
22206     getAllAncestors: function()
22207     {
22208         var p = this.getSelectedNode();
22209         var a = [];
22210         if (!p) {
22211             a.push(p); // push blank onto stack..
22212             p = this.getParentElement();
22213         }
22214         
22215         
22216         while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22217             a.push(p);
22218             p = p.parentNode;
22219         }
22220         a.push(this.doc.body);
22221         return a;
22222     },
22223     lastSel : false,
22224     lastSelNode : false,
22225     
22226     
22227     getSelection : function() 
22228     {
22229         this.assignDocWin();
22230         return Roo.isIE ? this.doc.selection : this.win.getSelection();
22231     },
22232     
22233     getSelectedNode: function() 
22234     {
22235         // this may only work on Gecko!!!
22236         
22237         // should we cache this!!!!
22238         
22239         
22240         
22241          
22242         var range = this.createRange(this.getSelection()).cloneRange();
22243         
22244         if (Roo.isIE) {
22245             var parent = range.parentElement();
22246             while (true) {
22247                 var testRange = range.duplicate();
22248                 testRange.moveToElementText(parent);
22249                 if (testRange.inRange(range)) {
22250                     break;
22251                 }
22252                 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22253                     break;
22254                 }
22255                 parent = parent.parentElement;
22256             }
22257             return parent;
22258         }
22259         
22260         // is ancestor a text element.
22261         var ac =  range.commonAncestorContainer;
22262         if (ac.nodeType == 3) {
22263             ac = ac.parentNode;
22264         }
22265         
22266         var ar = ac.childNodes;
22267          
22268         var nodes = [];
22269         var other_nodes = [];
22270         var has_other_nodes = false;
22271         for (var i=0;i<ar.length;i++) {
22272             if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ? 
22273                 continue;
22274             }
22275             // fullly contained node.
22276             
22277             if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22278                 nodes.push(ar[i]);
22279                 continue;
22280             }
22281             
22282             // probably selected..
22283             if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22284                 other_nodes.push(ar[i]);
22285                 continue;
22286             }
22287             // outer..
22288             if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0))  {
22289                 continue;
22290             }
22291             
22292             
22293             has_other_nodes = true;
22294         }
22295         if (!nodes.length && other_nodes.length) {
22296             nodes= other_nodes;
22297         }
22298         if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22299             return false;
22300         }
22301         
22302         return nodes[0];
22303     },
22304     createRange: function(sel)
22305     {
22306         // this has strange effects when using with 
22307         // top toolbar - not sure if it's a great idea.
22308         //this.editor.contentWindow.focus();
22309         if (typeof sel != "undefined") {
22310             try {
22311                 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22312             } catch(e) {
22313                 return this.doc.createRange();
22314             }
22315         } else {
22316             return this.doc.createRange();
22317         }
22318     },
22319     getParentElement: function()
22320     {
22321         
22322         this.assignDocWin();
22323         var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22324         
22325         var range = this.createRange(sel);
22326          
22327         try {
22328             var p = range.commonAncestorContainer;
22329             while (p.nodeType == 3) { // text node
22330                 p = p.parentNode;
22331             }
22332             return p;
22333         } catch (e) {
22334             return null;
22335         }
22336     
22337     },
22338     /***
22339      *
22340      * Range intersection.. the hard stuff...
22341      *  '-1' = before
22342      *  '0' = hits..
22343      *  '1' = after.
22344      *         [ -- selected range --- ]
22345      *   [fail]                        [fail]
22346      *
22347      *    basically..
22348      *      if end is before start or  hits it. fail.
22349      *      if start is after end or hits it fail.
22350      *
22351      *   if either hits (but other is outside. - then it's not 
22352      *   
22353      *    
22354      **/
22355     
22356     
22357     // @see http://www.thismuchiknow.co.uk/?p=64.
22358     rangeIntersectsNode : function(range, node)
22359     {
22360         var nodeRange = node.ownerDocument.createRange();
22361         try {
22362             nodeRange.selectNode(node);
22363         } catch (e) {
22364             nodeRange.selectNodeContents(node);
22365         }
22366     
22367         var rangeStartRange = range.cloneRange();
22368         rangeStartRange.collapse(true);
22369     
22370         var rangeEndRange = range.cloneRange();
22371         rangeEndRange.collapse(false);
22372     
22373         var nodeStartRange = nodeRange.cloneRange();
22374         nodeStartRange.collapse(true);
22375     
22376         var nodeEndRange = nodeRange.cloneRange();
22377         nodeEndRange.collapse(false);
22378     
22379         return rangeStartRange.compareBoundaryPoints(
22380                  Range.START_TO_START, nodeEndRange) == -1 &&
22381                rangeEndRange.compareBoundaryPoints(
22382                  Range.START_TO_START, nodeStartRange) == 1;
22383         
22384          
22385     },
22386     rangeCompareNode : function(range, node)
22387     {
22388         var nodeRange = node.ownerDocument.createRange();
22389         try {
22390             nodeRange.selectNode(node);
22391         } catch (e) {
22392             nodeRange.selectNodeContents(node);
22393         }
22394         
22395         
22396         range.collapse(true);
22397     
22398         nodeRange.collapse(true);
22399      
22400         var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22401         var ee = range.compareBoundaryPoints(  Range.END_TO_END, nodeRange);
22402          
22403         //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22404         
22405         var nodeIsBefore   =  ss == 1;
22406         var nodeIsAfter    = ee == -1;
22407         
22408         if (nodeIsBefore && nodeIsAfter) {
22409             return 0; // outer
22410         }
22411         if (!nodeIsBefore && nodeIsAfter) {
22412             return 1; //right trailed.
22413         }
22414         
22415         if (nodeIsBefore && !nodeIsAfter) {
22416             return 2;  // left trailed.
22417         }
22418         // fully contined.
22419         return 3;
22420     },
22421
22422     // private? - in a new class?
22423     cleanUpPaste :  function()
22424     {
22425         // cleans up the whole document..
22426         Roo.log('cleanuppaste');
22427         
22428         this.cleanUpChildren(this.doc.body);
22429         var clean = this.cleanWordChars(this.doc.body.innerHTML);
22430         if (clean != this.doc.body.innerHTML) {
22431             this.doc.body.innerHTML = clean;
22432         }
22433         
22434     },
22435     
22436     cleanWordChars : function(input) {// change the chars to hex code
22437         var he = Roo.HtmlEditorCore;
22438         
22439         var output = input;
22440         Roo.each(he.swapCodes, function(sw) { 
22441             var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22442             
22443             output = output.replace(swapper, sw[1]);
22444         });
22445         
22446         return output;
22447     },
22448     
22449     
22450     cleanUpChildren : function (n)
22451     {
22452         if (!n.childNodes.length) {
22453             return;
22454         }
22455         for (var i = n.childNodes.length-1; i > -1 ; i--) {
22456            this.cleanUpChild(n.childNodes[i]);
22457         }
22458     },
22459     
22460     
22461         
22462     
22463     cleanUpChild : function (node)
22464     {
22465         var ed = this;
22466         //console.log(node);
22467         if (node.nodeName == "#text") {
22468             // clean up silly Windows -- stuff?
22469             return; 
22470         }
22471         if (node.nodeName == "#comment") {
22472             node.parentNode.removeChild(node);
22473             // clean up silly Windows -- stuff?
22474             return; 
22475         }
22476         var lcname = node.tagName.toLowerCase();
22477         // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22478         // whitelist of tags..
22479         
22480         if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22481             // remove node.
22482             node.parentNode.removeChild(node);
22483             return;
22484             
22485         }
22486         
22487         var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22488         
22489         // remove <a name=....> as rendering on yahoo mailer is borked with this.
22490         // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22491         
22492         //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22493         //    remove_keep_children = true;
22494         //}
22495         
22496         if (remove_keep_children) {
22497             this.cleanUpChildren(node);
22498             // inserts everything just before this node...
22499             while (node.childNodes.length) {
22500                 var cn = node.childNodes[0];
22501                 node.removeChild(cn);
22502                 node.parentNode.insertBefore(cn, node);
22503             }
22504             node.parentNode.removeChild(node);
22505             return;
22506         }
22507         
22508         if (!node.attributes || !node.attributes.length) {
22509             this.cleanUpChildren(node);
22510             return;
22511         }
22512         
22513         function cleanAttr(n,v)
22514         {
22515             
22516             if (v.match(/^\./) || v.match(/^\//)) {
22517                 return;
22518             }
22519             if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22520                 return;
22521             }
22522             if (v.match(/^#/)) {
22523                 return;
22524             }
22525 //            Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22526             node.removeAttribute(n);
22527             
22528         }
22529         
22530         var cwhite = this.cwhite;
22531         var cblack = this.cblack;
22532             
22533         function cleanStyle(n,v)
22534         {
22535             if (v.match(/expression/)) { //XSS?? should we even bother..
22536                 node.removeAttribute(n);
22537                 return;
22538             }
22539             
22540             var parts = v.split(/;/);
22541             var clean = [];
22542             
22543             Roo.each(parts, function(p) {
22544                 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22545                 if (!p.length) {
22546                     return true;
22547                 }
22548                 var l = p.split(':').shift().replace(/\s+/g,'');
22549                 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22550                 
22551                 if ( cwhite.length && cblack.indexOf(l) > -1) {
22552 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22553                     //node.removeAttribute(n);
22554                     return true;
22555                 }
22556                 //Roo.log()
22557                 // only allow 'c whitelisted system attributes'
22558                 if ( cwhite.length &&  cwhite.indexOf(l) < 0) {
22559 //                    Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22560                     //node.removeAttribute(n);
22561                     return true;
22562                 }
22563                 
22564                 
22565                  
22566                 
22567                 clean.push(p);
22568                 return true;
22569             });
22570             if (clean.length) { 
22571                 node.setAttribute(n, clean.join(';'));
22572             } else {
22573                 node.removeAttribute(n);
22574             }
22575             
22576         }
22577         
22578         
22579         for (var i = node.attributes.length-1; i > -1 ; i--) {
22580             var a = node.attributes[i];
22581             //console.log(a);
22582             
22583             if (a.name.toLowerCase().substr(0,2)=='on')  {
22584                 node.removeAttribute(a.name);
22585                 continue;
22586             }
22587             if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22588                 node.removeAttribute(a.name);
22589                 continue;
22590             }
22591             if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22592                 cleanAttr(a.name,a.value); // fixme..
22593                 continue;
22594             }
22595             if (a.name == 'style') {
22596                 cleanStyle(a.name,a.value);
22597                 continue;
22598             }
22599             /// clean up MS crap..
22600             // tecnically this should be a list of valid class'es..
22601             
22602             
22603             if (a.name == 'class') {
22604                 if (a.value.match(/^Mso/)) {
22605                     node.className = '';
22606                 }
22607                 
22608                 if (a.value.match(/^body$/)) {
22609                     node.className = '';
22610                 }
22611                 continue;
22612             }
22613             
22614             // style cleanup!?
22615             // class cleanup?
22616             
22617         }
22618         
22619         
22620         this.cleanUpChildren(node);
22621         
22622         
22623     },
22624     
22625     /**
22626      * Clean up MS wordisms...
22627      */
22628     cleanWord : function(node)
22629     {
22630         
22631         
22632         if (!node) {
22633             this.cleanWord(this.doc.body);
22634             return;
22635         }
22636         if (node.nodeName == "#text") {
22637             // clean up silly Windows -- stuff?
22638             return; 
22639         }
22640         if (node.nodeName == "#comment") {
22641             node.parentNode.removeChild(node);
22642             // clean up silly Windows -- stuff?
22643             return; 
22644         }
22645         
22646         if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22647             node.parentNode.removeChild(node);
22648             return;
22649         }
22650         
22651         // remove - but keep children..
22652         if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22653             while (node.childNodes.length) {
22654                 var cn = node.childNodes[0];
22655                 node.removeChild(cn);
22656                 node.parentNode.insertBefore(cn, node);
22657             }
22658             node.parentNode.removeChild(node);
22659             this.iterateChildren(node, this.cleanWord);
22660             return;
22661         }
22662         // clean styles
22663         if (node.className.length) {
22664             
22665             var cn = node.className.split(/\W+/);
22666             var cna = [];
22667             Roo.each(cn, function(cls) {
22668                 if (cls.match(/Mso[a-zA-Z]+/)) {
22669                     return;
22670                 }
22671                 cna.push(cls);
22672             });
22673             node.className = cna.length ? cna.join(' ') : '';
22674             if (!cna.length) {
22675                 node.removeAttribute("class");
22676             }
22677         }
22678         
22679         if (node.hasAttribute("lang")) {
22680             node.removeAttribute("lang");
22681         }
22682         
22683         if (node.hasAttribute("style")) {
22684             
22685             var styles = node.getAttribute("style").split(";");
22686             var nstyle = [];
22687             Roo.each(styles, function(s) {
22688                 if (!s.match(/:/)) {
22689                     return;
22690                 }
22691                 var kv = s.split(":");
22692                 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22693                     return;
22694                 }
22695                 // what ever is left... we allow.
22696                 nstyle.push(s);
22697             });
22698             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22699             if (!nstyle.length) {
22700                 node.removeAttribute('style');
22701             }
22702         }
22703         this.iterateChildren(node, this.cleanWord);
22704         
22705         
22706         
22707     },
22708     /**
22709      * iterateChildren of a Node, calling fn each time, using this as the scole..
22710      * @param {DomNode} node node to iterate children of.
22711      * @param {Function} fn method of this class to call on each item.
22712      */
22713     iterateChildren : function(node, fn)
22714     {
22715         if (!node.childNodes.length) {
22716                 return;
22717         }
22718         for (var i = node.childNodes.length-1; i > -1 ; i--) {
22719            fn.call(this, node.childNodes[i])
22720         }
22721     },
22722     
22723     
22724     /**
22725      * cleanTableWidths.
22726      *
22727      * Quite often pasting from word etc.. results in tables with column and widths.
22728      * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22729      *
22730      */
22731     cleanTableWidths : function(node)
22732     {
22733          
22734          
22735         if (!node) {
22736             this.cleanTableWidths(this.doc.body);
22737             return;
22738         }
22739         
22740         // ignore list...
22741         if (node.nodeName == "#text" || node.nodeName == "#comment") {
22742             return; 
22743         }
22744         Roo.log(node.tagName);
22745         if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
22746             this.iterateChildren(node, this.cleanTableWidths);
22747             return;
22748         }
22749         if (node.hasAttribute('width')) {
22750             node.removeAttribute('width');
22751         }
22752         
22753          
22754         if (node.hasAttribute("style")) {
22755             // pretty basic...
22756             
22757             var styles = node.getAttribute("style").split(";");
22758             var nstyle = [];
22759             Roo.each(styles, function(s) {
22760                 if (!s.match(/:/)) {
22761                     return;
22762                 }
22763                 var kv = s.split(":");
22764                 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
22765                     return;
22766                 }
22767                 // what ever is left... we allow.
22768                 nstyle.push(s);
22769             });
22770             node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22771             if (!nstyle.length) {
22772                 node.removeAttribute('style');
22773             }
22774         }
22775         
22776         this.iterateChildren(node, this.cleanTableWidths);
22777         
22778         
22779     },
22780     
22781     
22782     
22783     
22784     domToHTML : function(currentElement, depth, nopadtext) {
22785         
22786         depth = depth || 0;
22787         nopadtext = nopadtext || false;
22788     
22789         if (!currentElement) {
22790             return this.domToHTML(this.doc.body);
22791         }
22792         
22793         //Roo.log(currentElement);
22794         var j;
22795         var allText = false;
22796         var nodeName = currentElement.nodeName;
22797         var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
22798         
22799         if  (nodeName == '#text') {
22800             
22801             return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
22802         }
22803         
22804         
22805         var ret = '';
22806         if (nodeName != 'BODY') {
22807              
22808             var i = 0;
22809             // Prints the node tagName, such as <A>, <IMG>, etc
22810             if (tagName) {
22811                 var attr = [];
22812                 for(i = 0; i < currentElement.attributes.length;i++) {
22813                     // quoting?
22814                     var aname = currentElement.attributes.item(i).name;
22815                     if (!currentElement.attributes.item(i).value.length) {
22816                         continue;
22817                     }
22818                     attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
22819                 }
22820                 
22821                 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
22822             } 
22823             else {
22824                 
22825                 // eack
22826             }
22827         } else {
22828             tagName = false;
22829         }
22830         if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
22831             return ret;
22832         }
22833         if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
22834             nopadtext = true;
22835         }
22836         
22837         
22838         // Traverse the tree
22839         i = 0;
22840         var currentElementChild = currentElement.childNodes.item(i);
22841         var allText = true;
22842         var innerHTML  = '';
22843         lastnode = '';
22844         while (currentElementChild) {
22845             // Formatting code (indent the tree so it looks nice on the screen)
22846             var nopad = nopadtext;
22847             if (lastnode == 'SPAN') {
22848                 nopad  = true;
22849             }
22850             // text
22851             if  (currentElementChild.nodeName == '#text') {
22852                 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
22853                 toadd = nopadtext ? toadd : toadd.trim();
22854                 if (!nopad && toadd.length > 80) {
22855                     innerHTML  += "\n" + (new Array( depth + 1 )).join( "  "  );
22856                 }
22857                 innerHTML  += toadd;
22858                 
22859                 i++;
22860                 currentElementChild = currentElement.childNodes.item(i);
22861                 lastNode = '';
22862                 continue;
22863             }
22864             allText = false;
22865             
22866             innerHTML  += nopad ? '' : "\n" + (new Array( depth + 1 )).join( "  "  );
22867                 
22868             // Recursively traverse the tree structure of the child node
22869             innerHTML   += this.domToHTML(currentElementChild, depth+1, nopadtext);
22870             lastnode = currentElementChild.nodeName;
22871             i++;
22872             currentElementChild=currentElement.childNodes.item(i);
22873         }
22874         
22875         ret += innerHTML;
22876         
22877         if (!allText) {
22878                 // The remaining code is mostly for formatting the tree
22879             ret+= nopadtext ? '' : "\n" + (new Array( depth  )).join( "  "  );
22880         }
22881         
22882         
22883         if (tagName) {
22884             ret+= "</"+tagName+">";
22885         }
22886         return ret;
22887         
22888     },
22889         
22890     applyBlacklists : function()
22891     {
22892         var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white  : [];
22893         var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black :  [];
22894         
22895         this.white = [];
22896         this.black = [];
22897         Roo.each(Roo.HtmlEditorCore.white, function(tag) {
22898             if (b.indexOf(tag) > -1) {
22899                 return;
22900             }
22901             this.white.push(tag);
22902             
22903         }, this);
22904         
22905         Roo.each(w, function(tag) {
22906             if (b.indexOf(tag) > -1) {
22907                 return;
22908             }
22909             if (this.white.indexOf(tag) > -1) {
22910                 return;
22911             }
22912             this.white.push(tag);
22913             
22914         }, this);
22915         
22916         
22917         Roo.each(Roo.HtmlEditorCore.black, function(tag) {
22918             if (w.indexOf(tag) > -1) {
22919                 return;
22920             }
22921             this.black.push(tag);
22922             
22923         }, this);
22924         
22925         Roo.each(b, function(tag) {
22926             if (w.indexOf(tag) > -1) {
22927                 return;
22928             }
22929             if (this.black.indexOf(tag) > -1) {
22930                 return;
22931             }
22932             this.black.push(tag);
22933             
22934         }, this);
22935         
22936         
22937         w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite  : [];
22938         b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack :  [];
22939         
22940         this.cwhite = [];
22941         this.cblack = [];
22942         Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
22943             if (b.indexOf(tag) > -1) {
22944                 return;
22945             }
22946             this.cwhite.push(tag);
22947             
22948         }, this);
22949         
22950         Roo.each(w, function(tag) {
22951             if (b.indexOf(tag) > -1) {
22952                 return;
22953             }
22954             if (this.cwhite.indexOf(tag) > -1) {
22955                 return;
22956             }
22957             this.cwhite.push(tag);
22958             
22959         }, this);
22960         
22961         
22962         Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
22963             if (w.indexOf(tag) > -1) {
22964                 return;
22965             }
22966             this.cblack.push(tag);
22967             
22968         }, this);
22969         
22970         Roo.each(b, function(tag) {
22971             if (w.indexOf(tag) > -1) {
22972                 return;
22973             }
22974             if (this.cblack.indexOf(tag) > -1) {
22975                 return;
22976             }
22977             this.cblack.push(tag);
22978             
22979         }, this);
22980     },
22981     
22982     setStylesheets : function(stylesheets)
22983     {
22984         if(typeof(stylesheets) == 'string'){
22985             Roo.get(this.iframe.contentDocument.head).createChild({
22986                 tag : 'link',
22987                 rel : 'stylesheet',
22988                 type : 'text/css',
22989                 href : stylesheets
22990             });
22991             
22992             return;
22993         }
22994         var _this = this;
22995      
22996         Roo.each(stylesheets, function(s) {
22997             if(!s.length){
22998                 return;
22999             }
23000             
23001             Roo.get(_this.iframe.contentDocument.head).createChild({
23002                 tag : 'link',
23003                 rel : 'stylesheet',
23004                 type : 'text/css',
23005                 href : s
23006             });
23007         });
23008
23009         
23010     },
23011     
23012     removeStylesheets : function()
23013     {
23014         var _this = this;
23015         
23016         Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23017             s.remove();
23018         });
23019     },
23020     
23021     setStyle : function(style)
23022     {
23023         Roo.get(this.iframe.contentDocument.head).createChild({
23024             tag : 'style',
23025             type : 'text/css',
23026             html : style
23027         });
23028
23029         return;
23030     }
23031     
23032     // hide stuff that is not compatible
23033     /**
23034      * @event blur
23035      * @hide
23036      */
23037     /**
23038      * @event change
23039      * @hide
23040      */
23041     /**
23042      * @event focus
23043      * @hide
23044      */
23045     /**
23046      * @event specialkey
23047      * @hide
23048      */
23049     /**
23050      * @cfg {String} fieldClass @hide
23051      */
23052     /**
23053      * @cfg {String} focusClass @hide
23054      */
23055     /**
23056      * @cfg {String} autoCreate @hide
23057      */
23058     /**
23059      * @cfg {String} inputType @hide
23060      */
23061     /**
23062      * @cfg {String} invalidClass @hide
23063      */
23064     /**
23065      * @cfg {String} invalidText @hide
23066      */
23067     /**
23068      * @cfg {String} msgFx @hide
23069      */
23070     /**
23071      * @cfg {String} validateOnBlur @hide
23072      */
23073 });
23074
23075 Roo.HtmlEditorCore.white = [
23076         'area', 'br', 'img', 'input', 'hr', 'wbr',
23077         
23078        'address', 'blockquote', 'center', 'dd',      'dir',       'div', 
23079        'dl',      'dt',         'h1',     'h2',      'h3',        'h4', 
23080        'h5',      'h6',         'hr',     'isindex', 'listing',   'marquee', 
23081        'menu',    'multicol',   'ol',     'p',       'plaintext', 'pre', 
23082        'table',   'ul',         'xmp', 
23083        
23084        'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', 
23085       'thead',   'tr', 
23086      
23087       'dir', 'menu', 'ol', 'ul', 'dl',
23088        
23089       'embed',  'object'
23090 ];
23091
23092
23093 Roo.HtmlEditorCore.black = [
23094     //    'embed',  'object', // enable - backend responsiblity to clean thiese
23095         'applet', // 
23096         'base',   'basefont', 'bgsound', 'blink',  'body', 
23097         'frame',  'frameset', 'head',    'html',   'ilayer', 
23098         'iframe', 'layer',  'link',     'meta',    'object',   
23099         'script', 'style' ,'title',  'xml' // clean later..
23100 ];
23101 Roo.HtmlEditorCore.clean = [
23102     'script', 'style', 'title', 'xml'
23103 ];
23104 Roo.HtmlEditorCore.remove = [
23105     'font'
23106 ];
23107 // attributes..
23108
23109 Roo.HtmlEditorCore.ablack = [
23110     'on'
23111 ];
23112     
23113 Roo.HtmlEditorCore.aclean = [ 
23114     'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc' 
23115 ];
23116
23117 // protocols..
23118 Roo.HtmlEditorCore.pwhite= [
23119         'http',  'https',  'mailto'
23120 ];
23121
23122 // white listed style attributes.
23123 Roo.HtmlEditorCore.cwhite= [
23124       //  'text-align', /// default is to allow most things..
23125       
23126          
23127 //        'font-size'//??
23128 ];
23129
23130 // black listed style attributes.
23131 Roo.HtmlEditorCore.cblack= [
23132       //  'font-size' -- this can be set by the project 
23133 ];
23134
23135
23136 Roo.HtmlEditorCore.swapCodes   =[ 
23137     [    8211, "--" ], 
23138     [    8212, "--" ], 
23139     [    8216,  "'" ],  
23140     [    8217, "'" ],  
23141     [    8220, '"' ],  
23142     [    8221, '"' ],  
23143     [    8226, "*" ],  
23144     [    8230, "..." ]
23145 ]; 
23146
23147     /*
23148  * - LGPL
23149  *
23150  * HtmlEditor
23151  * 
23152  */
23153
23154 /**
23155  * @class Roo.bootstrap.HtmlEditor
23156  * @extends Roo.bootstrap.TextArea
23157  * Bootstrap HtmlEditor class
23158
23159  * @constructor
23160  * Create a new HtmlEditor
23161  * @param {Object} config The config object
23162  */
23163
23164 Roo.bootstrap.HtmlEditor = function(config){
23165     Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23166     if (!this.toolbars) {
23167         this.toolbars = [];
23168     }
23169     
23170     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23171     this.addEvents({
23172             /**
23173              * @event initialize
23174              * Fires when the editor is fully initialized (including the iframe)
23175              * @param {HtmlEditor} this
23176              */
23177             initialize: true,
23178             /**
23179              * @event activate
23180              * Fires when the editor is first receives the focus. Any insertion must wait
23181              * until after this event.
23182              * @param {HtmlEditor} this
23183              */
23184             activate: true,
23185              /**
23186              * @event beforesync
23187              * Fires before the textarea is updated with content from the editor iframe. Return false
23188              * to cancel the sync.
23189              * @param {HtmlEditor} this
23190              * @param {String} html
23191              */
23192             beforesync: true,
23193              /**
23194              * @event beforepush
23195              * Fires before the iframe editor is updated with content from the textarea. Return false
23196              * to cancel the push.
23197              * @param {HtmlEditor} this
23198              * @param {String} html
23199              */
23200             beforepush: true,
23201              /**
23202              * @event sync
23203              * Fires when the textarea is updated with content from the editor iframe.
23204              * @param {HtmlEditor} this
23205              * @param {String} html
23206              */
23207             sync: true,
23208              /**
23209              * @event push
23210              * Fires when the iframe editor is updated with content from the textarea.
23211              * @param {HtmlEditor} this
23212              * @param {String} html
23213              */
23214             push: true,
23215              /**
23216              * @event editmodechange
23217              * Fires when the editor switches edit modes
23218              * @param {HtmlEditor} this
23219              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23220              */
23221             editmodechange: true,
23222             /**
23223              * @event editorevent
23224              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23225              * @param {HtmlEditor} this
23226              */
23227             editorevent: true,
23228             /**
23229              * @event firstfocus
23230              * Fires when on first focus - needed by toolbars..
23231              * @param {HtmlEditor} this
23232              */
23233             firstfocus: true,
23234             /**
23235              * @event autosave
23236              * Auto save the htmlEditor value as a file into Events
23237              * @param {HtmlEditor} this
23238              */
23239             autosave: true,
23240             /**
23241              * @event savedpreview
23242              * preview the saved version of htmlEditor
23243              * @param {HtmlEditor} this
23244              */
23245             savedpreview: true
23246         });
23247 };
23248
23249
23250 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea,  {
23251     
23252     
23253       /**
23254      * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23255      */
23256     toolbars : false,
23257     
23258      /**
23259     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23260     */
23261     btns : [],
23262    
23263      /**
23264      * @cfg {String} resizable  's' or 'se' or 'e' - wrapps the element in a
23265      *                        Roo.resizable.
23266      */
23267     resizable : false,
23268      /**
23269      * @cfg {Number} height (in pixels)
23270      */   
23271     height: 300,
23272    /**
23273      * @cfg {Number} width (in pixels)
23274      */   
23275     width: false,
23276     
23277     /**
23278      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23279      * 
23280      */
23281     stylesheets: false,
23282     
23283     // id of frame..
23284     frameId: false,
23285     
23286     // private properties
23287     validationEvent : false,
23288     deferHeight: true,
23289     initialized : false,
23290     activated : false,
23291     
23292     onFocus : Roo.emptyFn,
23293     iframePad:3,
23294     hideMode:'offsets',
23295     
23296     tbContainer : false,
23297     
23298     bodyCls : '',
23299     
23300     toolbarContainer :function() {
23301         return this.wrap.select('.x-html-editor-tb',true).first();
23302     },
23303
23304     /**
23305      * Protected method that will not generally be called directly. It
23306      * is called when the editor creates its toolbar. Override this method if you need to
23307      * add custom toolbar buttons.
23308      * @param {HtmlEditor} editor
23309      */
23310     createToolbar : function(){
23311         Roo.log('renewing');
23312         Roo.log("create toolbars");
23313         
23314         this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23315         this.toolbars[0].render(this.toolbarContainer());
23316         
23317         return;
23318         
23319 //        if (!editor.toolbars || !editor.toolbars.length) {
23320 //            editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23321 //        }
23322 //        
23323 //        for (var i =0 ; i < editor.toolbars.length;i++) {
23324 //            editor.toolbars[i] = Roo.factory(
23325 //                    typeof(editor.toolbars[i]) == 'string' ?
23326 //                        { xtype: editor.toolbars[i]} : editor.toolbars[i],
23327 //                Roo.bootstrap.HtmlEditor);
23328 //            editor.toolbars[i].init(editor);
23329 //        }
23330     },
23331
23332      
23333     // private
23334     onRender : function(ct, position)
23335     {
23336        // Roo.log("Call onRender: " + this.xtype);
23337         var _t = this;
23338         Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23339       
23340         this.wrap = this.inputEl().wrap({
23341             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23342         });
23343         
23344         this.editorcore.onRender(ct, position);
23345          
23346         if (this.resizable) {
23347             this.resizeEl = new Roo.Resizable(this.wrap, {
23348                 pinned : true,
23349                 wrap: true,
23350                 dynamic : true,
23351                 minHeight : this.height,
23352                 height: this.height,
23353                 handles : this.resizable,
23354                 width: this.width,
23355                 listeners : {
23356                     resize : function(r, w, h) {
23357                         _t.onResize(w,h); // -something
23358                     }
23359                 }
23360             });
23361             
23362         }
23363         this.createToolbar(this);
23364        
23365         
23366         if(!this.width && this.resizable){
23367             this.setSize(this.wrap.getSize());
23368         }
23369         if (this.resizeEl) {
23370             this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23371             // should trigger onReize..
23372         }
23373         
23374     },
23375
23376     // private
23377     onResize : function(w, h)
23378     {
23379         Roo.log('resize: ' +w + ',' + h );
23380         Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23381         var ew = false;
23382         var eh = false;
23383         
23384         if(this.inputEl() ){
23385             if(typeof w == 'number'){
23386                 var aw = w - this.wrap.getFrameWidth('lr');
23387                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23388                 ew = aw;
23389             }
23390             if(typeof h == 'number'){
23391                  var tbh = -11;  // fixme it needs to tool bar size!
23392                 for (var i =0; i < this.toolbars.length;i++) {
23393                     // fixme - ask toolbars for heights?
23394                     tbh += this.toolbars[i].el.getHeight();
23395                     //if (this.toolbars[i].footer) {
23396                     //    tbh += this.toolbars[i].footer.el.getHeight();
23397                     //}
23398                 }
23399               
23400                 
23401                 
23402                 
23403                 
23404                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23405                 ah -= 5; // knock a few pixes off for look..
23406                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23407                 var eh = ah;
23408             }
23409         }
23410         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23411         this.editorcore.onResize(ew,eh);
23412         
23413     },
23414
23415     /**
23416      * Toggles the editor between standard and source edit mode.
23417      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23418      */
23419     toggleSourceEdit : function(sourceEditMode)
23420     {
23421         this.editorcore.toggleSourceEdit(sourceEditMode);
23422         
23423         if(this.editorcore.sourceEditMode){
23424             Roo.log('editor - showing textarea');
23425             
23426 //            Roo.log('in');
23427 //            Roo.log(this.syncValue());
23428             this.syncValue();
23429             this.inputEl().removeClass(['hide', 'x-hidden']);
23430             this.inputEl().dom.removeAttribute('tabIndex');
23431             this.inputEl().focus();
23432         }else{
23433             Roo.log('editor - hiding textarea');
23434 //            Roo.log('out')
23435 //            Roo.log(this.pushValue()); 
23436             this.pushValue();
23437             
23438             this.inputEl().addClass(['hide', 'x-hidden']);
23439             this.inputEl().dom.setAttribute('tabIndex', -1);
23440             //this.deferFocus();
23441         }
23442          
23443         if(this.resizable){
23444             this.setSize(this.wrap.getSize());
23445         }
23446         
23447         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23448     },
23449  
23450     // private (for BoxComponent)
23451     adjustSize : Roo.BoxComponent.prototype.adjustSize,
23452
23453     // private (for BoxComponent)
23454     getResizeEl : function(){
23455         return this.wrap;
23456     },
23457
23458     // private (for BoxComponent)
23459     getPositionEl : function(){
23460         return this.wrap;
23461     },
23462
23463     // private
23464     initEvents : function(){
23465         this.originalValue = this.getValue();
23466     },
23467
23468 //    /**
23469 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23470 //     * @method
23471 //     */
23472 //    markInvalid : Roo.emptyFn,
23473 //    /**
23474 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23475 //     * @method
23476 //     */
23477 //    clearInvalid : Roo.emptyFn,
23478
23479     setValue : function(v){
23480         Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23481         this.editorcore.pushValue();
23482     },
23483
23484      
23485     // private
23486     deferFocus : function(){
23487         this.focus.defer(10, this);
23488     },
23489
23490     // doc'ed in Field
23491     focus : function(){
23492         this.editorcore.focus();
23493         
23494     },
23495       
23496
23497     // private
23498     onDestroy : function(){
23499         
23500         
23501         
23502         if(this.rendered){
23503             
23504             for (var i =0; i < this.toolbars.length;i++) {
23505                 // fixme - ask toolbars for heights?
23506                 this.toolbars[i].onDestroy();
23507             }
23508             
23509             this.wrap.dom.innerHTML = '';
23510             this.wrap.remove();
23511         }
23512     },
23513
23514     // private
23515     onFirstFocus : function(){
23516         //Roo.log("onFirstFocus");
23517         this.editorcore.onFirstFocus();
23518          for (var i =0; i < this.toolbars.length;i++) {
23519             this.toolbars[i].onFirstFocus();
23520         }
23521         
23522     },
23523     
23524     // private
23525     syncValue : function()
23526     {   
23527         this.editorcore.syncValue();
23528     },
23529     
23530     pushValue : function()
23531     {   
23532         this.editorcore.pushValue();
23533     }
23534      
23535     
23536     // hide stuff that is not compatible
23537     /**
23538      * @event blur
23539      * @hide
23540      */
23541     /**
23542      * @event change
23543      * @hide
23544      */
23545     /**
23546      * @event focus
23547      * @hide
23548      */
23549     /**
23550      * @event specialkey
23551      * @hide
23552      */
23553     /**
23554      * @cfg {String} fieldClass @hide
23555      */
23556     /**
23557      * @cfg {String} focusClass @hide
23558      */
23559     /**
23560      * @cfg {String} autoCreate @hide
23561      */
23562     /**
23563      * @cfg {String} inputType @hide
23564      */
23565     /**
23566      * @cfg {String} invalidClass @hide
23567      */
23568     /**
23569      * @cfg {String} invalidText @hide
23570      */
23571     /**
23572      * @cfg {String} msgFx @hide
23573      */
23574     /**
23575      * @cfg {String} validateOnBlur @hide
23576      */
23577 });
23578  
23579     
23580    
23581    
23582    
23583       
23584 Roo.namespace('Roo.bootstrap.htmleditor');
23585 /**
23586  * @class Roo.bootstrap.HtmlEditorToolbar1
23587  * Basic Toolbar
23588  * 
23589  * Usage:
23590  *
23591  new Roo.bootstrap.HtmlEditor({
23592     ....
23593     toolbars : [
23594         new Roo.bootstrap.HtmlEditorToolbar1({
23595             disable : { fonts: 1 , format: 1, ..., ... , ...],
23596             btns : [ .... ]
23597         })
23598     }
23599      
23600  * 
23601  * @cfg {Object} disable List of elements to disable..
23602  * @cfg {Array} btns List of additional buttons.
23603  * 
23604  * 
23605  * NEEDS Extra CSS? 
23606  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23607  */
23608  
23609 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23610 {
23611     
23612     Roo.apply(this, config);
23613     
23614     // default disabled, based on 'good practice'..
23615     this.disable = this.disable || {};
23616     Roo.applyIf(this.disable, {
23617         fontSize : true,
23618         colors : true,
23619         specialElements : true
23620     });
23621     Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23622     
23623     this.editor = config.editor;
23624     this.editorcore = config.editor.editorcore;
23625     
23626     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23627     
23628     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23629     // dont call parent... till later.
23630 }
23631 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar,  {
23632      
23633     bar : true,
23634     
23635     editor : false,
23636     editorcore : false,
23637     
23638     
23639     formats : [
23640         "p" ,  
23641         "h1","h2","h3","h4","h5","h6", 
23642         "pre", "code", 
23643         "abbr", "acronym", "address", "cite", "samp", "var",
23644         'div','span'
23645     ],
23646     
23647     onRender : function(ct, position)
23648     {
23649        // Roo.log("Call onRender: " + this.xtype);
23650         
23651        Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23652        Roo.log(this.el);
23653        this.el.dom.style.marginBottom = '0';
23654        var _this = this;
23655        var editorcore = this.editorcore;
23656        var editor= this.editor;
23657        
23658        var children = [];
23659        var btn = function(id,cmd , toggle, handler, html){
23660        
23661             var  event = toggle ? 'toggle' : 'click';
23662        
23663             var a = {
23664                 size : 'sm',
23665                 xtype: 'Button',
23666                 xns: Roo.bootstrap,
23667                 glyphicon : id,
23668                 cmd : id || cmd,
23669                 enableToggle:toggle !== false,
23670                 html : html || '',
23671                 pressed : toggle ? false : null,
23672                 listeners : {}
23673             };
23674             a.listeners[toggle ? 'toggle' : 'click'] = function() {
23675                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
23676             };
23677             children.push(a);
23678             return a;
23679        }
23680        
23681     //    var cb_box = function...
23682         
23683         var style = {
23684                 xtype: 'Button',
23685                 size : 'sm',
23686                 xns: Roo.bootstrap,
23687                 glyphicon : 'font',
23688                 //html : 'submit'
23689                 menu : {
23690                     xtype: 'Menu',
23691                     xns: Roo.bootstrap,
23692                     items:  []
23693                 }
23694         };
23695         Roo.each(this.formats, function(f) {
23696             style.menu.items.push({
23697                 xtype :'MenuItem',
23698                 xns: Roo.bootstrap,
23699                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23700                 tagname : f,
23701                 listeners : {
23702                     click : function()
23703                     {
23704                         editorcore.insertTag(this.tagname);
23705                         editor.focus();
23706                     }
23707                 }
23708                 
23709             });
23710         });
23711         children.push(style);   
23712         
23713         btn('bold',false,true);
23714         btn('italic',false,true);
23715         btn('align-left', 'justifyleft',true);
23716         btn('align-center', 'justifycenter',true);
23717         btn('align-right' , 'justifyright',true);
23718         btn('link', false, false, function(btn) {
23719             //Roo.log("create link?");
23720             var url = prompt(this.createLinkText, this.defaultLinkValue);
23721             if(url && url != 'http:/'+'/'){
23722                 this.editorcore.relayCmd('createlink', url);
23723             }
23724         }),
23725         btn('list','insertunorderedlist',true);
23726         btn('pencil', false,true, function(btn){
23727                 Roo.log(this);
23728                 this.toggleSourceEdit(btn.pressed);
23729         });
23730         
23731         if (this.editor.btns.length > 0) {
23732             for (var i = 0; i<this.editor.btns.length; i++) {
23733                 children.push(this.editor.btns[i]);
23734             }
23735         }
23736         
23737         /*
23738         var cog = {
23739                 xtype: 'Button',
23740                 size : 'sm',
23741                 xns: Roo.bootstrap,
23742                 glyphicon : 'cog',
23743                 //html : 'submit'
23744                 menu : {
23745                     xtype: 'Menu',
23746                     xns: Roo.bootstrap,
23747                     items:  []
23748                 }
23749         };
23750         
23751         cog.menu.items.push({
23752             xtype :'MenuItem',
23753             xns: Roo.bootstrap,
23754             html : Clean styles,
23755             tagname : f,
23756             listeners : {
23757                 click : function()
23758                 {
23759                     editorcore.insertTag(this.tagname);
23760                     editor.focus();
23761                 }
23762             }
23763             
23764         });
23765        */
23766         
23767          
23768        this.xtype = 'NavSimplebar';
23769         
23770         for(var i=0;i< children.length;i++) {
23771             
23772             this.buttons.add(this.addxtypeChild(children[i]));
23773             
23774         }
23775         
23776         editor.on('editorevent', this.updateToolbar, this);
23777     },
23778     onBtnClick : function(id)
23779     {
23780        this.editorcore.relayCmd(id);
23781        this.editorcore.focus();
23782     },
23783     
23784     /**
23785      * Protected method that will not generally be called directly. It triggers
23786      * a toolbar update by reading the markup state of the current selection in the editor.
23787      */
23788     updateToolbar: function(){
23789
23790         if(!this.editorcore.activated){
23791             this.editor.onFirstFocus(); // is this neeed?
23792             return;
23793         }
23794
23795         var btns = this.buttons; 
23796         var doc = this.editorcore.doc;
23797         btns.get('bold').setActive(doc.queryCommandState('bold'));
23798         btns.get('italic').setActive(doc.queryCommandState('italic'));
23799         //btns.get('underline').setActive(doc.queryCommandState('underline'));
23800         
23801         btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
23802         btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
23803         btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
23804         
23805         //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
23806         btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
23807          /*
23808         
23809         var ans = this.editorcore.getAllAncestors();
23810         if (this.formatCombo) {
23811             
23812             
23813             var store = this.formatCombo.store;
23814             this.formatCombo.setValue("");
23815             for (var i =0; i < ans.length;i++) {
23816                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
23817                     // select it..
23818                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
23819                     break;
23820                 }
23821             }
23822         }
23823         
23824         
23825         
23826         // hides menus... - so this cant be on a menu...
23827         Roo.bootstrap.MenuMgr.hideAll();
23828         */
23829         Roo.bootstrap.MenuMgr.hideAll();
23830         //this.editorsyncValue();
23831     },
23832     onFirstFocus: function() {
23833         this.buttons.each(function(item){
23834            item.enable();
23835         });
23836     },
23837     toggleSourceEdit : function(sourceEditMode){
23838         
23839           
23840         if(sourceEditMode){
23841             Roo.log("disabling buttons");
23842            this.buttons.each( function(item){
23843                 if(item.cmd != 'pencil'){
23844                     item.disable();
23845                 }
23846             });
23847           
23848         }else{
23849             Roo.log("enabling buttons");
23850             if(this.editorcore.initialized){
23851                 this.buttons.each( function(item){
23852                     item.enable();
23853                 });
23854             }
23855             
23856         }
23857         Roo.log("calling toggole on editor");
23858         // tell the editor that it's been pressed..
23859         this.editor.toggleSourceEdit(sourceEditMode);
23860        
23861     }
23862 });
23863
23864
23865
23866
23867
23868 /**
23869  * @class Roo.bootstrap.Table.AbstractSelectionModel
23870  * @extends Roo.util.Observable
23871  * Abstract base class for grid SelectionModels.  It provides the interface that should be
23872  * implemented by descendant classes.  This class should not be directly instantiated.
23873  * @constructor
23874  */
23875 Roo.bootstrap.Table.AbstractSelectionModel = function(){
23876     this.locked = false;
23877     Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
23878 };
23879
23880
23881 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable,  {
23882     /** @ignore Called by the grid automatically. Do not call directly. */
23883     init : function(grid){
23884         this.grid = grid;
23885         this.initEvents();
23886     },
23887
23888     /**
23889      * Locks the selections.
23890      */
23891     lock : function(){
23892         this.locked = true;
23893     },
23894
23895     /**
23896      * Unlocks the selections.
23897      */
23898     unlock : function(){
23899         this.locked = false;
23900     },
23901
23902     /**
23903      * Returns true if the selections are locked.
23904      * @return {Boolean}
23905      */
23906     isLocked : function(){
23907         return this.locked;
23908     }
23909 });
23910 /**
23911  * @extends Roo.bootstrap.Table.AbstractSelectionModel
23912  * @class Roo.bootstrap.Table.RowSelectionModel
23913  * The default SelectionModel used by {@link Roo.bootstrap.Table}.
23914  * It supports multiple selections and keyboard selection/navigation. 
23915  * @constructor
23916  * @param {Object} config
23917  */
23918
23919 Roo.bootstrap.Table.RowSelectionModel = function(config){
23920     Roo.apply(this, config);
23921     this.selections = new Roo.util.MixedCollection(false, function(o){
23922         return o.id;
23923     });
23924
23925     this.last = false;
23926     this.lastActive = false;
23927
23928     this.addEvents({
23929         /**
23930              * @event selectionchange
23931              * Fires when the selection changes
23932              * @param {SelectionModel} this
23933              */
23934             "selectionchange" : true,
23935         /**
23936              * @event afterselectionchange
23937              * Fires after the selection changes (eg. by key press or clicking)
23938              * @param {SelectionModel} this
23939              */
23940             "afterselectionchange" : true,
23941         /**
23942              * @event beforerowselect
23943              * Fires when a row is selected being selected, return false to cancel.
23944              * @param {SelectionModel} this
23945              * @param {Number} rowIndex The selected index
23946              * @param {Boolean} keepExisting False if other selections will be cleared
23947              */
23948             "beforerowselect" : true,
23949         /**
23950              * @event rowselect
23951              * Fires when a row is selected.
23952              * @param {SelectionModel} this
23953              * @param {Number} rowIndex The selected index
23954              * @param {Roo.data.Record} r The record
23955              */
23956             "rowselect" : true,
23957         /**
23958              * @event rowdeselect
23959              * Fires when a row is deselected.
23960              * @param {SelectionModel} this
23961              * @param {Number} rowIndex The selected index
23962              */
23963         "rowdeselect" : true
23964     });
23965     Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
23966     this.locked = false;
23967  };
23968
23969 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel,  {
23970     /**
23971      * @cfg {Boolean} singleSelect
23972      * True to allow selection of only one row at a time (defaults to false)
23973      */
23974     singleSelect : false,
23975
23976     // private
23977     initEvents : function()
23978     {
23979
23980         //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
23981         //    this.growclickrid.on("mousedown", this.handleMouseDown, this);
23982         //}else{ // allow click to work like normal
23983          //   this.grid.on("rowclick", this.handleDragableRowClick, this);
23984         //}
23985         //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
23986         this.grid.on("rowclick", this.handleMouseDown, this);
23987         
23988         this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
23989             "up" : function(e){
23990                 if(!e.shiftKey){
23991                     this.selectPrevious(e.shiftKey);
23992                 }else if(this.last !== false && this.lastActive !== false){
23993                     var last = this.last;
23994                     this.selectRange(this.last,  this.lastActive-1);
23995                     this.grid.getView().focusRow(this.lastActive);
23996                     if(last !== false){
23997                         this.last = last;
23998                     }
23999                 }else{
24000                     this.selectFirstRow();
24001                 }
24002                 this.fireEvent("afterselectionchange", this);
24003             },
24004             "down" : function(e){
24005                 if(!e.shiftKey){
24006                     this.selectNext(e.shiftKey);
24007                 }else if(this.last !== false && this.lastActive !== false){
24008                     var last = this.last;
24009                     this.selectRange(this.last,  this.lastActive+1);
24010                     this.grid.getView().focusRow(this.lastActive);
24011                     if(last !== false){
24012                         this.last = last;
24013                     }
24014                 }else{
24015                     this.selectFirstRow();
24016                 }
24017                 this.fireEvent("afterselectionchange", this);
24018             },
24019             scope: this
24020         });
24021         this.grid.store.on('load', function(){
24022             this.selections.clear();
24023         },this);
24024         /*
24025         var view = this.grid.view;
24026         view.on("refresh", this.onRefresh, this);
24027         view.on("rowupdated", this.onRowUpdated, this);
24028         view.on("rowremoved", this.onRemove, this);
24029         */
24030     },
24031
24032     // private
24033     onRefresh : function()
24034     {
24035         var ds = this.grid.store, i, v = this.grid.view;
24036         var s = this.selections;
24037         s.each(function(r){
24038             if((i = ds.indexOfId(r.id)) != -1){
24039                 v.onRowSelect(i);
24040             }else{
24041                 s.remove(r);
24042             }
24043         });
24044     },
24045
24046     // private
24047     onRemove : function(v, index, r){
24048         this.selections.remove(r);
24049     },
24050
24051     // private
24052     onRowUpdated : function(v, index, r){
24053         if(this.isSelected(r)){
24054             v.onRowSelect(index);
24055         }
24056     },
24057
24058     /**
24059      * Select records.
24060      * @param {Array} records The records to select
24061      * @param {Boolean} keepExisting (optional) True to keep existing selections
24062      */
24063     selectRecords : function(records, keepExisting)
24064     {
24065         if(!keepExisting){
24066             this.clearSelections();
24067         }
24068             var ds = this.grid.store;
24069         for(var i = 0, len = records.length; i < len; i++){
24070             this.selectRow(ds.indexOf(records[i]), true);
24071         }
24072     },
24073
24074     /**
24075      * Gets the number of selected rows.
24076      * @return {Number}
24077      */
24078     getCount : function(){
24079         return this.selections.length;
24080     },
24081
24082     /**
24083      * Selects the first row in the grid.
24084      */
24085     selectFirstRow : function(){
24086         this.selectRow(0);
24087     },
24088
24089     /**
24090      * Select the last row.
24091      * @param {Boolean} keepExisting (optional) True to keep existing selections
24092      */
24093     selectLastRow : function(keepExisting){
24094         //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24095         this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24096     },
24097
24098     /**
24099      * Selects the row immediately following the last selected row.
24100      * @param {Boolean} keepExisting (optional) True to keep existing selections
24101      */
24102     selectNext : function(keepExisting)
24103     {
24104             if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24105             this.selectRow(this.last+1, keepExisting);
24106             this.grid.getView().focusRow(this.last);
24107         }
24108     },
24109
24110     /**
24111      * Selects the row that precedes the last selected row.
24112      * @param {Boolean} keepExisting (optional) True to keep existing selections
24113      */
24114     selectPrevious : function(keepExisting){
24115         if(this.last){
24116             this.selectRow(this.last-1, keepExisting);
24117             this.grid.getView().focusRow(this.last);
24118         }
24119     },
24120
24121     /**
24122      * Returns the selected records
24123      * @return {Array} Array of selected records
24124      */
24125     getSelections : function(){
24126         return [].concat(this.selections.items);
24127     },
24128
24129     /**
24130      * Returns the first selected record.
24131      * @return {Record}
24132      */
24133     getSelected : function(){
24134         return this.selections.itemAt(0);
24135     },
24136
24137
24138     /**
24139      * Clears all selections.
24140      */
24141     clearSelections : function(fast)
24142     {
24143         if(this.locked) {
24144             return;
24145         }
24146         if(fast !== true){
24147                 var ds = this.grid.store;
24148             var s = this.selections;
24149             s.each(function(r){
24150                 this.deselectRow(ds.indexOfId(r.id));
24151             }, this);
24152             s.clear();
24153         }else{
24154             this.selections.clear();
24155         }
24156         this.last = false;
24157     },
24158
24159
24160     /**
24161      * Selects all rows.
24162      */
24163     selectAll : function(){
24164         if(this.locked) {
24165             return;
24166         }
24167         this.selections.clear();
24168         for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24169             this.selectRow(i, true);
24170         }
24171     },
24172
24173     /**
24174      * Returns True if there is a selection.
24175      * @return {Boolean}
24176      */
24177     hasSelection : function(){
24178         return this.selections.length > 0;
24179     },
24180
24181     /**
24182      * Returns True if the specified row is selected.
24183      * @param {Number/Record} record The record or index of the record to check
24184      * @return {Boolean}
24185      */
24186     isSelected : function(index){
24187             var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24188         return (r && this.selections.key(r.id) ? true : false);
24189     },
24190
24191     /**
24192      * Returns True if the specified record id is selected.
24193      * @param {String} id The id of record to check
24194      * @return {Boolean}
24195      */
24196     isIdSelected : function(id){
24197         return (this.selections.key(id) ? true : false);
24198     },
24199
24200
24201     // private
24202     handleMouseDBClick : function(e, t){
24203         
24204     },
24205     // private
24206     handleMouseDown : function(e, t)
24207     {
24208             var rowIndex = this.grid.headerShow  ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24209         if(this.isLocked() || rowIndex < 0 ){
24210             return;
24211         };
24212         if(e.shiftKey && this.last !== false){
24213             var last = this.last;
24214             this.selectRange(last, rowIndex, e.ctrlKey);
24215             this.last = last; // reset the last
24216             t.focus();
24217     
24218         }else{
24219             var isSelected = this.isSelected(rowIndex);
24220             //Roo.log("select row:" + rowIndex);
24221             if(isSelected){
24222                 this.deselectRow(rowIndex);
24223             } else {
24224                         this.selectRow(rowIndex, true);
24225             }
24226     
24227             /*
24228                 if(e.button !== 0 && isSelected){
24229                 alert('rowIndex 2: ' + rowIndex);
24230                     view.focusRow(rowIndex);
24231                 }else if(e.ctrlKey && isSelected){
24232                     this.deselectRow(rowIndex);
24233                 }else if(!isSelected){
24234                     this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24235                     view.focusRow(rowIndex);
24236                 }
24237             */
24238         }
24239         this.fireEvent("afterselectionchange", this);
24240     },
24241     // private
24242     handleDragableRowClick :  function(grid, rowIndex, e) 
24243     {
24244         if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24245             this.selectRow(rowIndex, false);
24246             grid.view.focusRow(rowIndex);
24247              this.fireEvent("afterselectionchange", this);
24248         }
24249     },
24250     
24251     /**
24252      * Selects multiple rows.
24253      * @param {Array} rows Array of the indexes of the row to select
24254      * @param {Boolean} keepExisting (optional) True to keep existing selections
24255      */
24256     selectRows : function(rows, keepExisting){
24257         if(!keepExisting){
24258             this.clearSelections();
24259         }
24260         for(var i = 0, len = rows.length; i < len; i++){
24261             this.selectRow(rows[i], true);
24262         }
24263     },
24264
24265     /**
24266      * Selects a range of rows. All rows in between startRow and endRow are also selected.
24267      * @param {Number} startRow The index of the first row in the range
24268      * @param {Number} endRow The index of the last row in the range
24269      * @param {Boolean} keepExisting (optional) True to retain existing selections
24270      */
24271     selectRange : function(startRow, endRow, keepExisting){
24272         if(this.locked) {
24273             return;
24274         }
24275         if(!keepExisting){
24276             this.clearSelections();
24277         }
24278         if(startRow <= endRow){
24279             for(var i = startRow; i <= endRow; i++){
24280                 this.selectRow(i, true);
24281             }
24282         }else{
24283             for(var i = startRow; i >= endRow; i--){
24284                 this.selectRow(i, true);
24285             }
24286         }
24287     },
24288
24289     /**
24290      * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24291      * @param {Number} startRow The index of the first row in the range
24292      * @param {Number} endRow The index of the last row in the range
24293      */
24294     deselectRange : function(startRow, endRow, preventViewNotify){
24295         if(this.locked) {
24296             return;
24297         }
24298         for(var i = startRow; i <= endRow; i++){
24299             this.deselectRow(i, preventViewNotify);
24300         }
24301     },
24302
24303     /**
24304      * Selects a row.
24305      * @param {Number} row The index of the row to select
24306      * @param {Boolean} keepExisting (optional) True to keep existing selections
24307      */
24308     selectRow : function(index, keepExisting, preventViewNotify)
24309     {
24310             if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24311             return;
24312         }
24313         if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24314             if(!keepExisting || this.singleSelect){
24315                 this.clearSelections();
24316             }
24317             
24318             var r = this.grid.store.getAt(index);
24319             //console.log('selectRow - record id :' + r.id);
24320             
24321             this.selections.add(r);
24322             this.last = this.lastActive = index;
24323             if(!preventViewNotify){
24324                 var proxy = new Roo.Element(
24325                                 this.grid.getRowDom(index)
24326                 );
24327                 proxy.addClass('bg-info info');
24328             }
24329             this.fireEvent("rowselect", this, index, r);
24330             this.fireEvent("selectionchange", this);
24331         }
24332     },
24333
24334     /**
24335      * Deselects a row.
24336      * @param {Number} row The index of the row to deselect
24337      */
24338     deselectRow : function(index, preventViewNotify)
24339     {
24340         if(this.locked) {
24341             return;
24342         }
24343         if(this.last == index){
24344             this.last = false;
24345         }
24346         if(this.lastActive == index){
24347             this.lastActive = false;
24348         }
24349         
24350         var r = this.grid.store.getAt(index);
24351         if (!r) {
24352             return;
24353         }
24354         
24355         this.selections.remove(r);
24356         //.console.log('deselectRow - record id :' + r.id);
24357         if(!preventViewNotify){
24358         
24359             var proxy = new Roo.Element(
24360                 this.grid.getRowDom(index)
24361             );
24362             proxy.removeClass('bg-info info');
24363         }
24364         this.fireEvent("rowdeselect", this, index);
24365         this.fireEvent("selectionchange", this);
24366     },
24367
24368     // private
24369     restoreLast : function(){
24370         if(this._last){
24371             this.last = this._last;
24372         }
24373     },
24374
24375     // private
24376     acceptsNav : function(row, col, cm){
24377         return !cm.isHidden(col) && cm.isCellEditable(col, row);
24378     },
24379
24380     // private
24381     onEditorKey : function(field, e){
24382         var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24383         if(k == e.TAB){
24384             e.stopEvent();
24385             ed.completeEdit();
24386             if(e.shiftKey){
24387                 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24388             }else{
24389                 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24390             }
24391         }else if(k == e.ENTER && !e.ctrlKey){
24392             e.stopEvent();
24393             ed.completeEdit();
24394             if(e.shiftKey){
24395                 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24396             }else{
24397                 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24398             }
24399         }else if(k == e.ESC){
24400             ed.cancelEdit();
24401         }
24402         if(newCell){
24403             g.startEditing(newCell[0], newCell[1]);
24404         }
24405     }
24406 });
24407 /*
24408  * Based on:
24409  * Ext JS Library 1.1.1
24410  * Copyright(c) 2006-2007, Ext JS, LLC.
24411  *
24412  * Originally Released Under LGPL - original licence link has changed is not relivant.
24413  *
24414  * Fork - LGPL
24415  * <script type="text/javascript">
24416  */
24417  
24418 /**
24419  * @class Roo.bootstrap.PagingToolbar
24420  * @extends Roo.bootstrap.NavSimplebar
24421  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24422  * @constructor
24423  * Create a new PagingToolbar
24424  * @param {Object} config The config object
24425  * @param {Roo.data.Store} store
24426  */
24427 Roo.bootstrap.PagingToolbar = function(config)
24428 {
24429     // old args format still supported... - xtype is prefered..
24430         // created from xtype...
24431     
24432     this.ds = config.dataSource;
24433     
24434     if (config.store && !this.ds) {
24435         this.store= Roo.factory(config.store, Roo.data);
24436         this.ds = this.store;
24437         this.ds.xmodule = this.xmodule || false;
24438     }
24439     
24440     this.toolbarItems = [];
24441     if (config.items) {
24442         this.toolbarItems = config.items;
24443     }
24444     
24445     Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24446     
24447     this.cursor = 0;
24448     
24449     if (this.ds) { 
24450         this.bind(this.ds);
24451     }
24452     
24453     this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24454     
24455 };
24456
24457 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24458     /**
24459      * @cfg {Roo.data.Store} dataSource
24460      * The underlying data store providing the paged data
24461      */
24462     /**
24463      * @cfg {String/HTMLElement/Element} container
24464      * container The id or element that will contain the toolbar
24465      */
24466     /**
24467      * @cfg {Boolean} displayInfo
24468      * True to display the displayMsg (defaults to false)
24469      */
24470     /**
24471      * @cfg {Number} pageSize
24472      * The number of records to display per page (defaults to 20)
24473      */
24474     pageSize: 20,
24475     /**
24476      * @cfg {String} displayMsg
24477      * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24478      */
24479     displayMsg : 'Displaying {0} - {1} of {2}',
24480     /**
24481      * @cfg {String} emptyMsg
24482      * The message to display when no records are found (defaults to "No data to display")
24483      */
24484     emptyMsg : 'No data to display',
24485     /**
24486      * Customizable piece of the default paging text (defaults to "Page")
24487      * @type String
24488      */
24489     beforePageText : "Page",
24490     /**
24491      * Customizable piece of the default paging text (defaults to "of %0")
24492      * @type String
24493      */
24494     afterPageText : "of {0}",
24495     /**
24496      * Customizable piece of the default paging text (defaults to "First Page")
24497      * @type String
24498      */
24499     firstText : "First Page",
24500     /**
24501      * Customizable piece of the default paging text (defaults to "Previous Page")
24502      * @type String
24503      */
24504     prevText : "Previous Page",
24505     /**
24506      * Customizable piece of the default paging text (defaults to "Next Page")
24507      * @type String
24508      */
24509     nextText : "Next Page",
24510     /**
24511      * Customizable piece of the default paging text (defaults to "Last Page")
24512      * @type String
24513      */
24514     lastText : "Last Page",
24515     /**
24516      * Customizable piece of the default paging text (defaults to "Refresh")
24517      * @type String
24518      */
24519     refreshText : "Refresh",
24520
24521     buttons : false,
24522     // private
24523     onRender : function(ct, position) 
24524     {
24525         Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24526         this.navgroup.parentId = this.id;
24527         this.navgroup.onRender(this.el, null);
24528         // add the buttons to the navgroup
24529         
24530         if(this.displayInfo){
24531             this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24532             this.displayEl = this.el.select('.x-paging-info', true).first();
24533 //            var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24534 //            this.displayEl = navel.el.select('span',true).first();
24535         }
24536         
24537         var _this = this;
24538         
24539         if(this.buttons){
24540             Roo.each(_this.buttons, function(e){ // this might need to use render????
24541                Roo.factory(e).render(_this.el);
24542             });
24543         }
24544             
24545         Roo.each(_this.toolbarItems, function(e) {
24546             _this.navgroup.addItem(e);
24547         });
24548         
24549         
24550         this.first = this.navgroup.addItem({
24551             tooltip: this.firstText,
24552             cls: "prev",
24553             icon : 'fa fa-backward',
24554             disabled: true,
24555             preventDefault: true,
24556             listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24557         });
24558         
24559         this.prev =  this.navgroup.addItem({
24560             tooltip: this.prevText,
24561             cls: "prev",
24562             icon : 'fa fa-step-backward',
24563             disabled: true,
24564             preventDefault: true,
24565             listeners : { click :  this.onClick.createDelegate(this, ["prev"]) }
24566         });
24567     //this.addSeparator();
24568         
24569         
24570         var field = this.navgroup.addItem( {
24571             tagtype : 'span',
24572             cls : 'x-paging-position',
24573             
24574             html : this.beforePageText  +
24575                 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24576                 '<span class="x-paging-after">' +  String.format(this.afterPageText, 1) + '</span>'
24577          } ); //?? escaped?
24578         
24579         this.field = field.el.select('input', true).first();
24580         this.field.on("keydown", this.onPagingKeydown, this);
24581         this.field.on("focus", function(){this.dom.select();});
24582     
24583     
24584         this.afterTextEl =  field.el.select('.x-paging-after',true).first();
24585         //this.field.setHeight(18);
24586         //this.addSeparator();
24587         this.next = this.navgroup.addItem({
24588             tooltip: this.nextText,
24589             cls: "next",
24590             html : ' <i class="fa fa-step-forward">',
24591             disabled: true,
24592             preventDefault: true,
24593             listeners : { click :  this.onClick.createDelegate(this, ["next"]) }
24594         });
24595         this.last = this.navgroup.addItem({
24596             tooltip: this.lastText,
24597             icon : 'fa fa-forward',
24598             cls: "next",
24599             disabled: true,
24600             preventDefault: true,
24601             listeners : { click :  this.onClick.createDelegate(this, ["last"]) }
24602         });
24603     //this.addSeparator();
24604         this.loading = this.navgroup.addItem({
24605             tooltip: this.refreshText,
24606             icon: 'fa fa-refresh',
24607             preventDefault: true,
24608             listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24609         });
24610         
24611     },
24612
24613     // private
24614     updateInfo : function(){
24615         if(this.displayEl){
24616             var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24617             var msg = count == 0 ?
24618                 this.emptyMsg :
24619                 String.format(
24620                     this.displayMsg,
24621                     this.cursor+1, this.cursor+count, this.ds.getTotalCount()    
24622                 );
24623             this.displayEl.update(msg);
24624         }
24625     },
24626
24627     // private
24628     onLoad : function(ds, r, o)
24629     {
24630         this.cursor = o.params.start ? o.params.start : 0;
24631         
24632         var d = this.getPageData(),
24633             ap = d.activePage,
24634             ps = d.pages;
24635         
24636         
24637         this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24638         this.field.dom.value = ap;
24639         this.first.setDisabled(ap == 1);
24640         this.prev.setDisabled(ap == 1);
24641         this.next.setDisabled(ap == ps);
24642         this.last.setDisabled(ap == ps);
24643         this.loading.enable();
24644         this.updateInfo();
24645     },
24646
24647     // private
24648     getPageData : function(){
24649         var total = this.ds.getTotalCount();
24650         return {
24651             total : total,
24652             activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24653             pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24654         };
24655     },
24656
24657     // private
24658     onLoadError : function(){
24659         this.loading.enable();
24660     },
24661
24662     // private
24663     onPagingKeydown : function(e){
24664         var k = e.getKey();
24665         var d = this.getPageData();
24666         if(k == e.RETURN){
24667             var v = this.field.dom.value, pageNum;
24668             if(!v || isNaN(pageNum = parseInt(v, 10))){
24669                 this.field.dom.value = d.activePage;
24670                 return;
24671             }
24672             pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24673             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24674             e.stopEvent();
24675         }
24676         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))
24677         {
24678           var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24679           this.field.dom.value = pageNum;
24680           this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24681           e.stopEvent();
24682         }
24683         else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24684         {
24685           var v = this.field.dom.value, pageNum; 
24686           var increment = (e.shiftKey) ? 10 : 1;
24687           if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24688                 increment *= -1;
24689           }
24690           if(!v || isNaN(pageNum = parseInt(v, 10))) {
24691             this.field.dom.value = d.activePage;
24692             return;
24693           }
24694           else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24695           {
24696             this.field.dom.value = parseInt(v, 10) + increment;
24697             pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24698             this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24699           }
24700           e.stopEvent();
24701         }
24702     },
24703
24704     // private
24705     beforeLoad : function(){
24706         if(this.loading){
24707             this.loading.disable();
24708         }
24709     },
24710
24711     // private
24712     onClick : function(which){
24713         
24714         var ds = this.ds;
24715         if (!ds) {
24716             return;
24717         }
24718         
24719         switch(which){
24720             case "first":
24721                 ds.load({params:{start: 0, limit: this.pageSize}});
24722             break;
24723             case "prev":
24724                 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24725             break;
24726             case "next":
24727                 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
24728             break;
24729             case "last":
24730                 var total = ds.getTotalCount();
24731                 var extra = total % this.pageSize;
24732                 var lastStart = extra ? (total - extra) : total-this.pageSize;
24733                 ds.load({params:{start: lastStart, limit: this.pageSize}});
24734             break;
24735             case "refresh":
24736                 ds.load({params:{start: this.cursor, limit: this.pageSize}});
24737             break;
24738         }
24739     },
24740
24741     /**
24742      * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
24743      * @param {Roo.data.Store} store The data store to unbind
24744      */
24745     unbind : function(ds){
24746         ds.un("beforeload", this.beforeLoad, this);
24747         ds.un("load", this.onLoad, this);
24748         ds.un("loadexception", this.onLoadError, this);
24749         ds.un("remove", this.updateInfo, this);
24750         ds.un("add", this.updateInfo, this);
24751         this.ds = undefined;
24752     },
24753
24754     /**
24755      * Binds the paging toolbar to the specified {@link Roo.data.Store}
24756      * @param {Roo.data.Store} store The data store to bind
24757      */
24758     bind : function(ds){
24759         ds.on("beforeload", this.beforeLoad, this);
24760         ds.on("load", this.onLoad, this);
24761         ds.on("loadexception", this.onLoadError, this);
24762         ds.on("remove", this.updateInfo, this);
24763         ds.on("add", this.updateInfo, this);
24764         this.ds = ds;
24765     }
24766 });/*
24767  * - LGPL
24768  *
24769  * element
24770  * 
24771  */
24772
24773 /**
24774  * @class Roo.bootstrap.MessageBar
24775  * @extends Roo.bootstrap.Component
24776  * Bootstrap MessageBar class
24777  * @cfg {String} html contents of the MessageBar
24778  * @cfg {String} weight (info | success | warning | danger) default info
24779  * @cfg {String} beforeClass insert the bar before the given class
24780  * @cfg {Boolean} closable (true | false) default false
24781  * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
24782  * 
24783  * @constructor
24784  * Create a new Element
24785  * @param {Object} config The config object
24786  */
24787
24788 Roo.bootstrap.MessageBar = function(config){
24789     Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
24790 };
24791
24792 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component,  {
24793     
24794     html: '',
24795     weight: 'info',
24796     closable: false,
24797     fixed: false,
24798     beforeClass: 'bootstrap-sticky-wrap',
24799     
24800     getAutoCreate : function(){
24801         
24802         var cfg = {
24803             tag: 'div',
24804             cls: 'alert alert-dismissable alert-' + this.weight,
24805             cn: [
24806                 {
24807                     tag: 'span',
24808                     cls: 'message',
24809                     html: this.html || ''
24810                 }
24811             ]
24812         };
24813         
24814         if(this.fixed){
24815             cfg.cls += ' alert-messages-fixed';
24816         }
24817         
24818         if(this.closable){
24819             cfg.cn.push({
24820                 tag: 'button',
24821                 cls: 'close',
24822                 html: 'x'
24823             });
24824         }
24825         
24826         return cfg;
24827     },
24828     
24829     onRender : function(ct, position)
24830     {
24831         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
24832         
24833         if(!this.el){
24834             var cfg = Roo.apply({},  this.getAutoCreate());
24835             cfg.id = Roo.id();
24836             
24837             if (this.cls) {
24838                 cfg.cls += ' ' + this.cls;
24839             }
24840             if (this.style) {
24841                 cfg.style = this.style;
24842             }
24843             this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
24844             
24845             this.el.setVisibilityMode(Roo.Element.DISPLAY);
24846         }
24847         
24848         this.el.select('>button.close').on('click', this.hide, this);
24849         
24850     },
24851     
24852     show : function()
24853     {
24854         if (!this.rendered) {
24855             this.render();
24856         }
24857         
24858         this.el.show();
24859         
24860         this.fireEvent('show', this);
24861         
24862     },
24863     
24864     hide : function()
24865     {
24866         if (!this.rendered) {
24867             this.render();
24868         }
24869         
24870         this.el.hide();
24871         
24872         this.fireEvent('hide', this);
24873     },
24874     
24875     update : function()
24876     {
24877 //        var e = this.el.dom.firstChild;
24878 //        
24879 //        if(this.closable){
24880 //            e = e.nextSibling;
24881 //        }
24882 //        
24883 //        e.data = this.html || '';
24884
24885         this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
24886     }
24887    
24888 });
24889
24890  
24891
24892      /*
24893  * - LGPL
24894  *
24895  * Graph
24896  * 
24897  */
24898
24899
24900 /**
24901  * @class Roo.bootstrap.Graph
24902  * @extends Roo.bootstrap.Component
24903  * Bootstrap Graph class
24904 > Prameters
24905  -sm {number} sm 4
24906  -md {number} md 5
24907  @cfg {String} graphtype  bar | vbar | pie
24908  @cfg {number} g_x coodinator | centre x (pie)
24909  @cfg {number} g_y coodinator | centre y (pie)
24910  @cfg {number} g_r radius (pie)
24911  @cfg {number} g_height height of the chart (respected by all elements in the set)
24912  @cfg {number} g_width width of the chart (respected by all elements in the set)
24913  @cfg {Object} title The title of the chart
24914     
24915  -{Array}  values
24916  -opts (object) options for the chart 
24917      o {
24918      o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
24919      o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
24920      o vgutter (number)
24921      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.
24922      o stacked (boolean) whether or not to tread values as in a stacked bar chart
24923      o to
24924      o stretch (boolean)
24925      o }
24926  -opts (object) options for the pie
24927      o{
24928      o cut
24929      o startAngle (number)
24930      o endAngle (number)
24931      } 
24932  *
24933  * @constructor
24934  * Create a new Input
24935  * @param {Object} config The config object
24936  */
24937
24938 Roo.bootstrap.Graph = function(config){
24939     Roo.bootstrap.Graph.superclass.constructor.call(this, config);
24940     
24941     this.addEvents({
24942         // img events
24943         /**
24944          * @event click
24945          * The img click event for the img.
24946          * @param {Roo.EventObject} e
24947          */
24948         "click" : true
24949     });
24950 };
24951
24952 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component,  {
24953     
24954     sm: 4,
24955     md: 5,
24956     graphtype: 'bar',
24957     g_height: 250,
24958     g_width: 400,
24959     g_x: 50,
24960     g_y: 50,
24961     g_r: 30,
24962     opts:{
24963         //g_colors: this.colors,
24964         g_type: 'soft',
24965         g_gutter: '20%'
24966
24967     },
24968     title : false,
24969
24970     getAutoCreate : function(){
24971         
24972         var cfg = {
24973             tag: 'div',
24974             html : null
24975         };
24976         
24977         
24978         return  cfg;
24979     },
24980
24981     onRender : function(ct,position){
24982         
24983         
24984         Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
24985         
24986         if (typeof(Raphael) == 'undefined') {
24987             Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
24988             return;
24989         }
24990         
24991         this.raphael = Raphael(this.el.dom);
24992         
24993                     // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24994                     // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24995                     // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
24996                     // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
24997                 /*
24998                 r.text(160, 10, "Single Series Chart").attr(txtattr);
24999                 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25000                 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25001                 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25002                 
25003                 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25004                 r.barchart(330, 10, 300, 220, data1);
25005                 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25006                 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25007                 */
25008                 
25009                 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25010                 // r.barchart(30, 30, 560, 250,  xdata, {
25011                 //    labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25012                 //     axis : "0 0 1 1",
25013                 //     axisxlabels :  xdata
25014                 //     //yvalues : cols,
25015                    
25016                 // });
25017 //        var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25018 //        
25019 //        this.load(null,xdata,{
25020 //                axis : "0 0 1 1",
25021 //                axisxlabels :  xdata
25022 //                });
25023
25024     },
25025
25026     load : function(graphtype,xdata,opts)
25027     {
25028         this.raphael.clear();
25029         if(!graphtype) {
25030             graphtype = this.graphtype;
25031         }
25032         if(!opts){
25033             opts = this.opts;
25034         }
25035         var r = this.raphael,
25036             fin = function () {
25037                 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25038             },
25039             fout = function () {
25040                 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25041             },
25042             pfin = function() {
25043                 this.sector.stop();
25044                 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25045
25046                 if (this.label) {
25047                     this.label[0].stop();
25048                     this.label[0].attr({ r: 7.5 });
25049                     this.label[1].attr({ "font-weight": 800 });
25050                 }
25051             },
25052             pfout = function() {
25053                 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25054
25055                 if (this.label) {
25056                     this.label[0].animate({ r: 5 }, 500, "bounce");
25057                     this.label[1].attr({ "font-weight": 400 });
25058                 }
25059             };
25060
25061         switch(graphtype){
25062             case 'bar':
25063                 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25064                 break;
25065             case 'hbar':
25066                 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25067                 break;
25068             case 'pie':
25069 //                opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west", 
25070 //                href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25071 //            
25072                 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25073                 
25074                 break;
25075
25076         }
25077         
25078         if(this.title){
25079             this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25080         }
25081         
25082     },
25083     
25084     setTitle: function(o)
25085     {
25086         this.title = o;
25087     },
25088     
25089     initEvents: function() {
25090         
25091         if(!this.href){
25092             this.el.on('click', this.onClick, this);
25093         }
25094     },
25095     
25096     onClick : function(e)
25097     {
25098         Roo.log('img onclick');
25099         this.fireEvent('click', this, e);
25100     }
25101    
25102 });
25103
25104  
25105 /*
25106  * - LGPL
25107  *
25108  * numberBox
25109  * 
25110  */
25111 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25112
25113 /**
25114  * @class Roo.bootstrap.dash.NumberBox
25115  * @extends Roo.bootstrap.Component
25116  * Bootstrap NumberBox class
25117  * @cfg {String} headline Box headline
25118  * @cfg {String} content Box content
25119  * @cfg {String} icon Box icon
25120  * @cfg {String} footer Footer text
25121  * @cfg {String} fhref Footer href
25122  * 
25123  * @constructor
25124  * Create a new NumberBox
25125  * @param {Object} config The config object
25126  */
25127
25128
25129 Roo.bootstrap.dash.NumberBox = function(config){
25130     Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25131     
25132 };
25133
25134 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component,  {
25135     
25136     headline : '',
25137     content : '',
25138     icon : '',
25139     footer : '',
25140     fhref : '',
25141     ficon : '',
25142     
25143     getAutoCreate : function(){
25144         
25145         var cfg = {
25146             tag : 'div',
25147             cls : 'small-box ',
25148             cn : [
25149                 {
25150                     tag : 'div',
25151                     cls : 'inner',
25152                     cn :[
25153                         {
25154                             tag : 'h3',
25155                             cls : 'roo-headline',
25156                             html : this.headline
25157                         },
25158                         {
25159                             tag : 'p',
25160                             cls : 'roo-content',
25161                             html : this.content
25162                         }
25163                     ]
25164                 }
25165             ]
25166         };
25167         
25168         if(this.icon){
25169             cfg.cn.push({
25170                 tag : 'div',
25171                 cls : 'icon',
25172                 cn :[
25173                     {
25174                         tag : 'i',
25175                         cls : 'ion ' + this.icon
25176                     }
25177                 ]
25178             });
25179         }
25180         
25181         if(this.footer){
25182             var footer = {
25183                 tag : 'a',
25184                 cls : 'small-box-footer',
25185                 href : this.fhref || '#',
25186                 html : this.footer
25187             };
25188             
25189             cfg.cn.push(footer);
25190             
25191         }
25192         
25193         return  cfg;
25194     },
25195
25196     onRender : function(ct,position){
25197         Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25198
25199
25200        
25201                 
25202     },
25203
25204     setHeadline: function (value)
25205     {
25206         this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25207     },
25208     
25209     setFooter: function (value, href)
25210     {
25211         this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25212         
25213         if(href){
25214             this.el.select('a.small-box-footer',true).first().attr('href', href);
25215         }
25216         
25217     },
25218
25219     setContent: function (value)
25220     {
25221         this.el.select('.roo-content',true).first().dom.innerHTML = value;
25222     },
25223
25224     initEvents: function() 
25225     {   
25226         
25227     }
25228     
25229 });
25230
25231  
25232 /*
25233  * - LGPL
25234  *
25235  * TabBox
25236  * 
25237  */
25238 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25239
25240 /**
25241  * @class Roo.bootstrap.dash.TabBox
25242  * @extends Roo.bootstrap.Component
25243  * Bootstrap TabBox class
25244  * @cfg {String} title Title of the TabBox
25245  * @cfg {String} icon Icon of the TabBox
25246  * @cfg {Boolean} showtabs (true|false) show the tabs default true
25247  * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25248  * 
25249  * @constructor
25250  * Create a new TabBox
25251  * @param {Object} config The config object
25252  */
25253
25254
25255 Roo.bootstrap.dash.TabBox = function(config){
25256     Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25257     this.addEvents({
25258         // raw events
25259         /**
25260          * @event addpane
25261          * When a pane is added
25262          * @param {Roo.bootstrap.dash.TabPane} pane
25263          */
25264         "addpane" : true,
25265         /**
25266          * @event activatepane
25267          * When a pane is activated
25268          * @param {Roo.bootstrap.dash.TabPane} pane
25269          */
25270         "activatepane" : true
25271         
25272          
25273     });
25274     
25275     this.panes = [];
25276 };
25277
25278 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component,  {
25279
25280     title : '',
25281     icon : false,
25282     showtabs : true,
25283     tabScrollable : false,
25284     
25285     getChildContainer : function()
25286     {
25287         return this.el.select('.tab-content', true).first();
25288     },
25289     
25290     getAutoCreate : function(){
25291         
25292         var header = {
25293             tag: 'li',
25294             cls: 'pull-left header',
25295             html: this.title,
25296             cn : []
25297         };
25298         
25299         if(this.icon){
25300             header.cn.push({
25301                 tag: 'i',
25302                 cls: 'fa ' + this.icon
25303             });
25304         }
25305         
25306         var h = {
25307             tag: 'ul',
25308             cls: 'nav nav-tabs pull-right',
25309             cn: [
25310                 header
25311             ]
25312         };
25313         
25314         if(this.tabScrollable){
25315             h = {
25316                 tag: 'div',
25317                 cls: 'tab-header',
25318                 cn: [
25319                     {
25320                         tag: 'ul',
25321                         cls: 'nav nav-tabs pull-right',
25322                         cn: [
25323                             header
25324                         ]
25325                     }
25326                 ]
25327             };
25328         }
25329         
25330         var cfg = {
25331             tag: 'div',
25332             cls: 'nav-tabs-custom',
25333             cn: [
25334                 h,
25335                 {
25336                     tag: 'div',
25337                     cls: 'tab-content no-padding',
25338                     cn: []
25339                 }
25340             ]
25341         };
25342
25343         return  cfg;
25344     },
25345     initEvents : function()
25346     {
25347         //Roo.log('add add pane handler');
25348         this.on('addpane', this.onAddPane, this);
25349     },
25350      /**
25351      * Updates the box title
25352      * @param {String} html to set the title to.
25353      */
25354     setTitle : function(value)
25355     {
25356         this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25357     },
25358     onAddPane : function(pane)
25359     {
25360         this.panes.push(pane);
25361         //Roo.log('addpane');
25362         //Roo.log(pane);
25363         // tabs are rendere left to right..
25364         if(!this.showtabs){
25365             return;
25366         }
25367         
25368         var ctr = this.el.select('.nav-tabs', true).first();
25369          
25370          
25371         var existing = ctr.select('.nav-tab',true);
25372         var qty = existing.getCount();;
25373         
25374         
25375         var tab = ctr.createChild({
25376             tag : 'li',
25377             cls : 'nav-tab' + (qty ? '' : ' active'),
25378             cn : [
25379                 {
25380                     tag : 'a',
25381                     href:'#',
25382                     html : pane.title
25383                 }
25384             ]
25385         }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25386         pane.tab = tab;
25387         
25388         tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25389         if (!qty) {
25390             pane.el.addClass('active');
25391         }
25392         
25393                 
25394     },
25395     onTabClick : function(ev,un,ob,pane)
25396     {
25397         //Roo.log('tab - prev default');
25398         ev.preventDefault();
25399         
25400         
25401         this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25402         pane.tab.addClass('active');
25403         //Roo.log(pane.title);
25404         this.getChildContainer().select('.tab-pane',true).removeClass('active');
25405         // technically we should have a deactivate event.. but maybe add later.
25406         // and it should not de-activate the selected tab...
25407         this.fireEvent('activatepane', pane);
25408         pane.el.addClass('active');
25409         pane.fireEvent('activate');
25410         
25411         
25412     },
25413     
25414     getActivePane : function()
25415     {
25416         var r = false;
25417         Roo.each(this.panes, function(p) {
25418             if(p.el.hasClass('active')){
25419                 r = p;
25420                 return false;
25421             }
25422             
25423             return;
25424         });
25425         
25426         return r;
25427     }
25428     
25429     
25430 });
25431
25432  
25433 /*
25434  * - LGPL
25435  *
25436  * Tab pane
25437  * 
25438  */
25439 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25440 /**
25441  * @class Roo.bootstrap.TabPane
25442  * @extends Roo.bootstrap.Component
25443  * Bootstrap TabPane class
25444  * @cfg {Boolean} active (false | true) Default false
25445  * @cfg {String} title title of panel
25446
25447  * 
25448  * @constructor
25449  * Create a new TabPane
25450  * @param {Object} config The config object
25451  */
25452
25453 Roo.bootstrap.dash.TabPane = function(config){
25454     Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25455     
25456     this.addEvents({
25457         // raw events
25458         /**
25459          * @event activate
25460          * When a pane is activated
25461          * @param {Roo.bootstrap.dash.TabPane} pane
25462          */
25463         "activate" : true
25464          
25465     });
25466 };
25467
25468 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component,  {
25469     
25470     active : false,
25471     title : '',
25472     
25473     // the tabBox that this is attached to.
25474     tab : false,
25475      
25476     getAutoCreate : function() 
25477     {
25478         var cfg = {
25479             tag: 'div',
25480             cls: 'tab-pane'
25481         };
25482         
25483         if(this.active){
25484             cfg.cls += ' active';
25485         }
25486         
25487         return cfg;
25488     },
25489     initEvents  : function()
25490     {
25491         //Roo.log('trigger add pane handler');
25492         this.parent().fireEvent('addpane', this)
25493     },
25494     
25495      /**
25496      * Updates the tab title 
25497      * @param {String} html to set the title to.
25498      */
25499     setTitle: function(str)
25500     {
25501         if (!this.tab) {
25502             return;
25503         }
25504         this.title = str;
25505         this.tab.select('a', true).first().dom.innerHTML = str;
25506         
25507     }
25508     
25509     
25510     
25511 });
25512
25513  
25514
25515
25516  /*
25517  * - LGPL
25518  *
25519  * menu
25520  * 
25521  */
25522 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25523
25524 /**
25525  * @class Roo.bootstrap.menu.Menu
25526  * @extends Roo.bootstrap.Component
25527  * Bootstrap Menu class - container for Menu
25528  * @cfg {String} html Text of the menu
25529  * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25530  * @cfg {String} icon Font awesome icon
25531  * @cfg {String} pos Menu align to (top | bottom) default bottom
25532  * 
25533  * 
25534  * @constructor
25535  * Create a new Menu
25536  * @param {Object} config The config object
25537  */
25538
25539
25540 Roo.bootstrap.menu.Menu = function(config){
25541     Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25542     
25543     this.addEvents({
25544         /**
25545          * @event beforeshow
25546          * Fires before this menu is displayed
25547          * @param {Roo.bootstrap.menu.Menu} this
25548          */
25549         beforeshow : true,
25550         /**
25551          * @event beforehide
25552          * Fires before this menu is hidden
25553          * @param {Roo.bootstrap.menu.Menu} this
25554          */
25555         beforehide : true,
25556         /**
25557          * @event show
25558          * Fires after this menu is displayed
25559          * @param {Roo.bootstrap.menu.Menu} this
25560          */
25561         show : true,
25562         /**
25563          * @event hide
25564          * Fires after this menu is hidden
25565          * @param {Roo.bootstrap.menu.Menu} this
25566          */
25567         hide : true,
25568         /**
25569          * @event click
25570          * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25571          * @param {Roo.bootstrap.menu.Menu} this
25572          * @param {Roo.EventObject} e
25573          */
25574         click : true
25575     });
25576     
25577 };
25578
25579 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component,  {
25580     
25581     submenu : false,
25582     html : '',
25583     weight : 'default',
25584     icon : false,
25585     pos : 'bottom',
25586     
25587     
25588     getChildContainer : function() {
25589         if(this.isSubMenu){
25590             return this.el;
25591         }
25592         
25593         return this.el.select('ul.dropdown-menu', true).first();  
25594     },
25595     
25596     getAutoCreate : function()
25597     {
25598         var text = [
25599             {
25600                 tag : 'span',
25601                 cls : 'roo-menu-text',
25602                 html : this.html
25603             }
25604         ];
25605         
25606         if(this.icon){
25607             text.unshift({
25608                 tag : 'i',
25609                 cls : 'fa ' + this.icon
25610             })
25611         }
25612         
25613         
25614         var cfg = {
25615             tag : 'div',
25616             cls : 'btn-group',
25617             cn : [
25618                 {
25619                     tag : 'button',
25620                     cls : 'dropdown-button btn btn-' + this.weight,
25621                     cn : text
25622                 },
25623                 {
25624                     tag : 'button',
25625                     cls : 'dropdown-toggle btn btn-' + this.weight,
25626                     cn : [
25627                         {
25628                             tag : 'span',
25629                             cls : 'caret'
25630                         }
25631                     ]
25632                 },
25633                 {
25634                     tag : 'ul',
25635                     cls : 'dropdown-menu'
25636                 }
25637             ]
25638             
25639         };
25640         
25641         if(this.pos == 'top'){
25642             cfg.cls += ' dropup';
25643         }
25644         
25645         if(this.isSubMenu){
25646             cfg = {
25647                 tag : 'ul',
25648                 cls : 'dropdown-menu'
25649             }
25650         }
25651         
25652         return cfg;
25653     },
25654     
25655     onRender : function(ct, position)
25656     {
25657         this.isSubMenu = ct.hasClass('dropdown-submenu');
25658         
25659         Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25660     },
25661     
25662     initEvents : function() 
25663     {
25664         if(this.isSubMenu){
25665             return;
25666         }
25667         
25668         this.hidden = true;
25669         
25670         this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25671         this.triggerEl.on('click', this.onTriggerPress, this);
25672         
25673         this.buttonEl = this.el.select('button.dropdown-button', true).first();
25674         this.buttonEl.on('click', this.onClick, this);
25675         
25676     },
25677     
25678     list : function()
25679     {
25680         if(this.isSubMenu){
25681             return this.el;
25682         }
25683         
25684         return this.el.select('ul.dropdown-menu', true).first();
25685     },
25686     
25687     onClick : function(e)
25688     {
25689         this.fireEvent("click", this, e);
25690     },
25691     
25692     onTriggerPress  : function(e)
25693     {   
25694         if (this.isVisible()) {
25695             this.hide();
25696         } else {
25697             this.show();
25698         }
25699     },
25700     
25701     isVisible : function(){
25702         return !this.hidden;
25703     },
25704     
25705     show : function()
25706     {
25707         this.fireEvent("beforeshow", this);
25708         
25709         this.hidden = false;
25710         this.el.addClass('open');
25711         
25712         Roo.get(document).on("mouseup", this.onMouseUp, this);
25713         
25714         this.fireEvent("show", this);
25715         
25716         
25717     },
25718     
25719     hide : function()
25720     {
25721         this.fireEvent("beforehide", this);
25722         
25723         this.hidden = true;
25724         this.el.removeClass('open');
25725         
25726         Roo.get(document).un("mouseup", this.onMouseUp);
25727         
25728         this.fireEvent("hide", this);
25729     },
25730     
25731     onMouseUp : function()
25732     {
25733         this.hide();
25734     }
25735     
25736 });
25737
25738  
25739  /*
25740  * - LGPL
25741  *
25742  * menu item
25743  * 
25744  */
25745 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25746
25747 /**
25748  * @class Roo.bootstrap.menu.Item
25749  * @extends Roo.bootstrap.Component
25750  * Bootstrap MenuItem class
25751  * @cfg {Boolean} submenu (true | false) default false
25752  * @cfg {String} html text of the item
25753  * @cfg {String} href the link
25754  * @cfg {Boolean} disable (true | false) default false
25755  * @cfg {Boolean} preventDefault (true | false) default true
25756  * @cfg {String} icon Font awesome icon
25757  * @cfg {String} pos Submenu align to (left | right) default right 
25758  * 
25759  * 
25760  * @constructor
25761  * Create a new Item
25762  * @param {Object} config The config object
25763  */
25764
25765
25766 Roo.bootstrap.menu.Item = function(config){
25767     Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
25768     this.addEvents({
25769         /**
25770          * @event mouseover
25771          * Fires when the mouse is hovering over this menu
25772          * @param {Roo.bootstrap.menu.Item} this
25773          * @param {Roo.EventObject} e
25774          */
25775         mouseover : true,
25776         /**
25777          * @event mouseout
25778          * Fires when the mouse exits this menu
25779          * @param {Roo.bootstrap.menu.Item} this
25780          * @param {Roo.EventObject} e
25781          */
25782         mouseout : true,
25783         // raw events
25784         /**
25785          * @event click
25786          * The raw click event for the entire grid.
25787          * @param {Roo.EventObject} e
25788          */
25789         click : true
25790     });
25791 };
25792
25793 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component,  {
25794     
25795     submenu : false,
25796     href : '',
25797     html : '',
25798     preventDefault: true,
25799     disable : false,
25800     icon : false,
25801     pos : 'right',
25802     
25803     getAutoCreate : function()
25804     {
25805         var text = [
25806             {
25807                 tag : 'span',
25808                 cls : 'roo-menu-item-text',
25809                 html : this.html
25810             }
25811         ];
25812         
25813         if(this.icon){
25814             text.unshift({
25815                 tag : 'i',
25816                 cls : 'fa ' + this.icon
25817             })
25818         }
25819         
25820         var cfg = {
25821             tag : 'li',
25822             cn : [
25823                 {
25824                     tag : 'a',
25825                     href : this.href || '#',
25826                     cn : text
25827                 }
25828             ]
25829         };
25830         
25831         if(this.disable){
25832             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
25833         }
25834         
25835         if(this.submenu){
25836             cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
25837             
25838             if(this.pos == 'left'){
25839                 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
25840             }
25841         }
25842         
25843         return cfg;
25844     },
25845     
25846     initEvents : function() 
25847     {
25848         this.el.on('mouseover', this.onMouseOver, this);
25849         this.el.on('mouseout', this.onMouseOut, this);
25850         
25851         this.el.select('a', true).first().on('click', this.onClick, this);
25852         
25853     },
25854     
25855     onClick : function(e)
25856     {
25857         if(this.preventDefault){
25858             e.preventDefault();
25859         }
25860         
25861         this.fireEvent("click", this, e);
25862     },
25863     
25864     onMouseOver : function(e)
25865     {
25866         if(this.submenu && this.pos == 'left'){
25867             this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
25868         }
25869         
25870         this.fireEvent("mouseover", this, e);
25871     },
25872     
25873     onMouseOut : function(e)
25874     {
25875         this.fireEvent("mouseout", this, e);
25876     }
25877 });
25878
25879  
25880
25881  /*
25882  * - LGPL
25883  *
25884  * menu separator
25885  * 
25886  */
25887 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25888
25889 /**
25890  * @class Roo.bootstrap.menu.Separator
25891  * @extends Roo.bootstrap.Component
25892  * Bootstrap Separator class
25893  * 
25894  * @constructor
25895  * Create a new Separator
25896  * @param {Object} config The config object
25897  */
25898
25899
25900 Roo.bootstrap.menu.Separator = function(config){
25901     Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
25902 };
25903
25904 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component,  {
25905     
25906     getAutoCreate : function(){
25907         var cfg = {
25908             tag : 'li',
25909             cls: 'divider'
25910         };
25911         
25912         return cfg;
25913     }
25914    
25915 });
25916
25917  
25918
25919  /*
25920  * - LGPL
25921  *
25922  * Tooltip
25923  * 
25924  */
25925
25926 /**
25927  * @class Roo.bootstrap.Tooltip
25928  * Bootstrap Tooltip class
25929  * This is basic at present - all componets support it by default, however they should add tooltipEl() method
25930  * to determine which dom element triggers the tooltip.
25931  * 
25932  * It needs to add support for additional attributes like tooltip-position
25933  * 
25934  * @constructor
25935  * Create a new Toolti
25936  * @param {Object} config The config object
25937  */
25938
25939 Roo.bootstrap.Tooltip = function(config){
25940     Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
25941     
25942     this.alignment = Roo.bootstrap.Tooltip.alignment;
25943     
25944     if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
25945         this.alignment = config.alignment;
25946     }
25947     
25948 };
25949
25950 Roo.apply(Roo.bootstrap.Tooltip, {
25951     /**
25952      * @function init initialize tooltip monitoring.
25953      * @static
25954      */
25955     currentEl : false,
25956     currentTip : false,
25957     currentRegion : false,
25958     
25959     //  init : delay?
25960     
25961     init : function()
25962     {
25963         Roo.get(document).on('mouseover', this.enter ,this);
25964         Roo.get(document).on('mouseout', this.leave, this);
25965          
25966         
25967         this.currentTip = new Roo.bootstrap.Tooltip();
25968     },
25969     
25970     enter : function(ev)
25971     {
25972         var dom = ev.getTarget();
25973         
25974         //Roo.log(['enter',dom]);
25975         var el = Roo.fly(dom);
25976         if (this.currentEl) {
25977             //Roo.log(dom);
25978             //Roo.log(this.currentEl);
25979             //Roo.log(this.currentEl.contains(dom));
25980             if (this.currentEl == el) {
25981                 return;
25982             }
25983             if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
25984                 return;
25985             }
25986
25987         }
25988         
25989         if (this.currentTip.el) {
25990             this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
25991         }    
25992         //Roo.log(ev);
25993         
25994         if(!el || el.dom == document){
25995             return;
25996         }
25997         
25998         var bindEl = el;
25999         
26000         // you can not look for children, as if el is the body.. then everythign is the child..
26001         if (!el.attr('tooltip')) { //
26002             if (!el.select("[tooltip]").elements.length) {
26003                 return;
26004             }
26005             // is the mouse over this child...?
26006             bindEl = el.select("[tooltip]").first();
26007             var xy = ev.getXY();
26008             if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26009                 //Roo.log("not in region.");
26010                 return;
26011             }
26012             //Roo.log("child element over..");
26013             
26014         }
26015         this.currentEl = bindEl;
26016         this.currentTip.bind(bindEl);
26017         this.currentRegion = Roo.lib.Region.getRegion(dom);
26018         this.currentTip.enter();
26019         
26020     },
26021     leave : function(ev)
26022     {
26023         var dom = ev.getTarget();
26024         //Roo.log(['leave',dom]);
26025         if (!this.currentEl) {
26026             return;
26027         }
26028         
26029         
26030         if (dom != this.currentEl.dom) {
26031             return;
26032         }
26033         var xy = ev.getXY();
26034         if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0]  ))) {
26035             return;
26036         }
26037         // only activate leave if mouse cursor is outside... bounding box..
26038         
26039         
26040         
26041         
26042         if (this.currentTip) {
26043             this.currentTip.leave();
26044         }
26045         //Roo.log('clear currentEl');
26046         this.currentEl = false;
26047         
26048         
26049     },
26050     alignment : {
26051         'left' : ['r-l', [-2,0], 'right'],
26052         'right' : ['l-r', [2,0], 'left'],
26053         'bottom' : ['t-b', [0,2], 'top'],
26054         'top' : [ 'b-t', [0,-2], 'bottom']
26055     }
26056     
26057 });
26058
26059
26060 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component,  {
26061     
26062     
26063     bindEl : false,
26064     
26065     delay : null, // can be { show : 300 , hide: 500}
26066     
26067     timeout : null,
26068     
26069     hoverState : null, //???
26070     
26071     placement : 'bottom', 
26072     
26073     alignment : false,
26074     
26075     getAutoCreate : function(){
26076     
26077         var cfg = {
26078            cls : 'tooltip',
26079            role : 'tooltip',
26080            cn : [
26081                 {
26082                     cls : 'tooltip-arrow'
26083                 },
26084                 {
26085                     cls : 'tooltip-inner'
26086                 }
26087            ]
26088         };
26089         
26090         return cfg;
26091     },
26092     bind : function(el)
26093     {
26094         this.bindEl = el;
26095     },
26096       
26097     
26098     enter : function () {
26099        
26100         if (this.timeout != null) {
26101             clearTimeout(this.timeout);
26102         }
26103         
26104         this.hoverState = 'in';
26105          //Roo.log("enter - show");
26106         if (!this.delay || !this.delay.show) {
26107             this.show();
26108             return;
26109         }
26110         var _t = this;
26111         this.timeout = setTimeout(function () {
26112             if (_t.hoverState == 'in') {
26113                 _t.show();
26114             }
26115         }, this.delay.show);
26116     },
26117     leave : function()
26118     {
26119         clearTimeout(this.timeout);
26120     
26121         this.hoverState = 'out';
26122          if (!this.delay || !this.delay.hide) {
26123             this.hide();
26124             return;
26125         }
26126        
26127         var _t = this;
26128         this.timeout = setTimeout(function () {
26129             //Roo.log("leave - timeout");
26130             
26131             if (_t.hoverState == 'out') {
26132                 _t.hide();
26133                 Roo.bootstrap.Tooltip.currentEl = false;
26134             }
26135         }, delay);
26136     },
26137     
26138     show : function (msg)
26139     {
26140         if (!this.el) {
26141             this.render(document.body);
26142         }
26143         // set content.
26144         //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26145         
26146         var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26147         
26148         this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26149         
26150         this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26151         
26152         var placement = typeof this.placement == 'function' ?
26153             this.placement.call(this, this.el, on_el) :
26154             this.placement;
26155             
26156         var autoToken = /\s?auto?\s?/i;
26157         var autoPlace = autoToken.test(placement);
26158         if (autoPlace) {
26159             placement = placement.replace(autoToken, '') || 'top';
26160         }
26161         
26162         //this.el.detach()
26163         //this.el.setXY([0,0]);
26164         this.el.show();
26165         //this.el.dom.style.display='block';
26166         
26167         //this.el.appendTo(on_el);
26168         
26169         var p = this.getPosition();
26170         var box = this.el.getBox();
26171         
26172         if (autoPlace) {
26173             // fixme..
26174         }
26175         
26176         var align = this.alignment[placement];
26177         
26178         var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26179         
26180         if(placement == 'top' || placement == 'bottom'){
26181             if(xy[0] < 0){
26182                 placement = 'right';
26183             }
26184             
26185             if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26186                 placement = 'left';
26187             }
26188             
26189             var scroll = Roo.select('body', true).first().getScroll();
26190             
26191             if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26192                 placement = 'top';
26193             }
26194             
26195         }
26196         
26197         this.el.alignTo(this.bindEl, align[0],align[1]);
26198         //var arrow = this.el.select('.arrow',true).first();
26199         //arrow.set(align[2], 
26200         
26201         this.el.addClass(placement);
26202         
26203         this.el.addClass('in fade');
26204         
26205         this.hoverState = null;
26206         
26207         if (this.el.hasClass('fade')) {
26208             // fade it?
26209         }
26210         
26211     },
26212     hide : function()
26213     {
26214          
26215         if (!this.el) {
26216             return;
26217         }
26218         //this.el.setXY([0,0]);
26219         this.el.removeClass('in');
26220         //this.el.hide();
26221         
26222     }
26223     
26224 });
26225  
26226
26227  /*
26228  * - LGPL
26229  *
26230  * Location Picker
26231  * 
26232  */
26233
26234 /**
26235  * @class Roo.bootstrap.LocationPicker
26236  * @extends Roo.bootstrap.Component
26237  * Bootstrap LocationPicker class
26238  * @cfg {Number} latitude Position when init default 0
26239  * @cfg {Number} longitude Position when init default 0
26240  * @cfg {Number} zoom default 15
26241  * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26242  * @cfg {Boolean} mapTypeControl default false
26243  * @cfg {Boolean} disableDoubleClickZoom default false
26244  * @cfg {Boolean} scrollwheel default true
26245  * @cfg {Boolean} streetViewControl default false
26246  * @cfg {Number} radius default 0
26247  * @cfg {String} locationName
26248  * @cfg {Boolean} draggable default true
26249  * @cfg {Boolean} enableAutocomplete default false
26250  * @cfg {Boolean} enableReverseGeocode default true
26251  * @cfg {String} markerTitle
26252  * 
26253  * @constructor
26254  * Create a new LocationPicker
26255  * @param {Object} config The config object
26256  */
26257
26258
26259 Roo.bootstrap.LocationPicker = function(config){
26260     
26261     Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26262     
26263     this.addEvents({
26264         /**
26265          * @event initial
26266          * Fires when the picker initialized.
26267          * @param {Roo.bootstrap.LocationPicker} this
26268          * @param {Google Location} location
26269          */
26270         initial : true,
26271         /**
26272          * @event positionchanged
26273          * Fires when the picker position changed.
26274          * @param {Roo.bootstrap.LocationPicker} this
26275          * @param {Google Location} location
26276          */
26277         positionchanged : true,
26278         /**
26279          * @event resize
26280          * Fires when the map resize.
26281          * @param {Roo.bootstrap.LocationPicker} this
26282          */
26283         resize : true,
26284         /**
26285          * @event show
26286          * Fires when the map show.
26287          * @param {Roo.bootstrap.LocationPicker} this
26288          */
26289         show : true,
26290         /**
26291          * @event hide
26292          * Fires when the map hide.
26293          * @param {Roo.bootstrap.LocationPicker} this
26294          */
26295         hide : true,
26296         /**
26297          * @event mapClick
26298          * Fires when click the map.
26299          * @param {Roo.bootstrap.LocationPicker} this
26300          * @param {Map event} e
26301          */
26302         mapClick : true,
26303         /**
26304          * @event mapRightClick
26305          * Fires when right click the map.
26306          * @param {Roo.bootstrap.LocationPicker} this
26307          * @param {Map event} e
26308          */
26309         mapRightClick : true,
26310         /**
26311          * @event markerClick
26312          * Fires when click the marker.
26313          * @param {Roo.bootstrap.LocationPicker} this
26314          * @param {Map event} e
26315          */
26316         markerClick : true,
26317         /**
26318          * @event markerRightClick
26319          * Fires when right click the marker.
26320          * @param {Roo.bootstrap.LocationPicker} this
26321          * @param {Map event} e
26322          */
26323         markerRightClick : true,
26324         /**
26325          * @event OverlayViewDraw
26326          * Fires when OverlayView Draw
26327          * @param {Roo.bootstrap.LocationPicker} this
26328          */
26329         OverlayViewDraw : true,
26330         /**
26331          * @event OverlayViewOnAdd
26332          * Fires when OverlayView Draw
26333          * @param {Roo.bootstrap.LocationPicker} this
26334          */
26335         OverlayViewOnAdd : true,
26336         /**
26337          * @event OverlayViewOnRemove
26338          * Fires when OverlayView Draw
26339          * @param {Roo.bootstrap.LocationPicker} this
26340          */
26341         OverlayViewOnRemove : true,
26342         /**
26343          * @event OverlayViewShow
26344          * Fires when OverlayView Draw
26345          * @param {Roo.bootstrap.LocationPicker} this
26346          * @param {Pixel} cpx
26347          */
26348         OverlayViewShow : true,
26349         /**
26350          * @event OverlayViewHide
26351          * Fires when OverlayView Draw
26352          * @param {Roo.bootstrap.LocationPicker} this
26353          */
26354         OverlayViewHide : true,
26355         /**
26356          * @event loadexception
26357          * Fires when load google lib failed.
26358          * @param {Roo.bootstrap.LocationPicker} this
26359          */
26360         loadexception : true
26361     });
26362         
26363 };
26364
26365 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component,  {
26366     
26367     gMapContext: false,
26368     
26369     latitude: 0,
26370     longitude: 0,
26371     zoom: 15,
26372     mapTypeId: false,
26373     mapTypeControl: false,
26374     disableDoubleClickZoom: false,
26375     scrollwheel: true,
26376     streetViewControl: false,
26377     radius: 0,
26378     locationName: '',
26379     draggable: true,
26380     enableAutocomplete: false,
26381     enableReverseGeocode: true,
26382     markerTitle: '',
26383     
26384     getAutoCreate: function()
26385     {
26386
26387         var cfg = {
26388             tag: 'div',
26389             cls: 'roo-location-picker'
26390         };
26391         
26392         return cfg
26393     },
26394     
26395     initEvents: function(ct, position)
26396     {       
26397         if(!this.el.getWidth() || this.isApplied()){
26398             return;
26399         }
26400         
26401         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26402         
26403         this.initial();
26404     },
26405     
26406     initial: function()
26407     {
26408         if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26409             this.fireEvent('loadexception', this);
26410             return;
26411         }
26412         
26413         if(!this.mapTypeId){
26414             this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26415         }
26416         
26417         this.gMapContext = this.GMapContext();
26418         
26419         this.initOverlayView();
26420         
26421         this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26422         
26423         var _this = this;
26424                 
26425         google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26426             _this.setPosition(_this.gMapContext.marker.position);
26427         });
26428         
26429         google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26430             _this.fireEvent('mapClick', this, event);
26431             
26432         });
26433
26434         google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26435             _this.fireEvent('mapRightClick', this, event);
26436             
26437         });
26438         
26439         google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26440             _this.fireEvent('markerClick', this, event);
26441             
26442         });
26443
26444         google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26445             _this.fireEvent('markerRightClick', this, event);
26446             
26447         });
26448         
26449         this.setPosition(this.gMapContext.location);
26450         
26451         this.fireEvent('initial', this, this.gMapContext.location);
26452     },
26453     
26454     initOverlayView: function()
26455     {
26456         var _this = this;
26457         
26458         Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26459             
26460             draw: function()
26461             {
26462                 _this.fireEvent('OverlayViewDraw', _this);
26463             },
26464             
26465             onAdd: function()
26466             {
26467                 _this.fireEvent('OverlayViewOnAdd', _this);
26468             },
26469             
26470             onRemove: function()
26471             {
26472                 _this.fireEvent('OverlayViewOnRemove', _this);
26473             },
26474             
26475             show: function(cpx)
26476             {
26477                 _this.fireEvent('OverlayViewShow', _this, cpx);
26478             },
26479             
26480             hide: function()
26481             {
26482                 _this.fireEvent('OverlayViewHide', _this);
26483             }
26484             
26485         });
26486     },
26487     
26488     fromLatLngToContainerPixel: function(event)
26489     {
26490         return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26491     },
26492     
26493     isApplied: function() 
26494     {
26495         return this.getGmapContext() == false ? false : true;
26496     },
26497     
26498     getGmapContext: function() 
26499     {
26500         return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26501     },
26502     
26503     GMapContext: function() 
26504     {
26505         var position = new google.maps.LatLng(this.latitude, this.longitude);
26506         
26507         var _map = new google.maps.Map(this.el.dom, {
26508             center: position,
26509             zoom: this.zoom,
26510             mapTypeId: this.mapTypeId,
26511             mapTypeControl: this.mapTypeControl,
26512             disableDoubleClickZoom: this.disableDoubleClickZoom,
26513             scrollwheel: this.scrollwheel,
26514             streetViewControl: this.streetViewControl,
26515             locationName: this.locationName,
26516             draggable: this.draggable,
26517             enableAutocomplete: this.enableAutocomplete,
26518             enableReverseGeocode: this.enableReverseGeocode
26519         });
26520         
26521         var _marker = new google.maps.Marker({
26522             position: position,
26523             map: _map,
26524             title: this.markerTitle,
26525             draggable: this.draggable
26526         });
26527         
26528         return {
26529             map: _map,
26530             marker: _marker,
26531             circle: null,
26532             location: position,
26533             radius: this.radius,
26534             locationName: this.locationName,
26535             addressComponents: {
26536                 formatted_address: null,
26537                 addressLine1: null,
26538                 addressLine2: null,
26539                 streetName: null,
26540                 streetNumber: null,
26541                 city: null,
26542                 district: null,
26543                 state: null,
26544                 stateOrProvince: null
26545             },
26546             settings: this,
26547             domContainer: this.el.dom,
26548             geodecoder: new google.maps.Geocoder()
26549         };
26550     },
26551     
26552     drawCircle: function(center, radius, options) 
26553     {
26554         if (this.gMapContext.circle != null) {
26555             this.gMapContext.circle.setMap(null);
26556         }
26557         if (radius > 0) {
26558             radius *= 1;
26559             options = Roo.apply({}, options, {
26560                 strokeColor: "#0000FF",
26561                 strokeOpacity: .35,
26562                 strokeWeight: 2,
26563                 fillColor: "#0000FF",
26564                 fillOpacity: .2
26565             });
26566             
26567             options.map = this.gMapContext.map;
26568             options.radius = radius;
26569             options.center = center;
26570             this.gMapContext.circle = new google.maps.Circle(options);
26571             return this.gMapContext.circle;
26572         }
26573         
26574         return null;
26575     },
26576     
26577     setPosition: function(location) 
26578     {
26579         this.gMapContext.location = location;
26580         this.gMapContext.marker.setPosition(location);
26581         this.gMapContext.map.panTo(location);
26582         this.drawCircle(location, this.gMapContext.radius, {});
26583         
26584         var _this = this;
26585         
26586         if (this.gMapContext.settings.enableReverseGeocode) {
26587             this.gMapContext.geodecoder.geocode({
26588                 latLng: this.gMapContext.location
26589             }, function(results, status) {
26590                 
26591                 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26592                     _this.gMapContext.locationName = results[0].formatted_address;
26593                     _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26594                     
26595                     _this.fireEvent('positionchanged', this, location);
26596                 }
26597             });
26598             
26599             return;
26600         }
26601         
26602         this.fireEvent('positionchanged', this, location);
26603     },
26604     
26605     resize: function()
26606     {
26607         google.maps.event.trigger(this.gMapContext.map, "resize");
26608         
26609         this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26610         
26611         this.fireEvent('resize', this);
26612     },
26613     
26614     setPositionByLatLng: function(latitude, longitude)
26615     {
26616         this.setPosition(new google.maps.LatLng(latitude, longitude));
26617     },
26618     
26619     getCurrentPosition: function() 
26620     {
26621         return {
26622             latitude: this.gMapContext.location.lat(),
26623             longitude: this.gMapContext.location.lng()
26624         };
26625     },
26626     
26627     getAddressName: function() 
26628     {
26629         return this.gMapContext.locationName;
26630     },
26631     
26632     getAddressComponents: function() 
26633     {
26634         return this.gMapContext.addressComponents;
26635     },
26636     
26637     address_component_from_google_geocode: function(address_components) 
26638     {
26639         var result = {};
26640         
26641         for (var i = 0; i < address_components.length; i++) {
26642             var component = address_components[i];
26643             if (component.types.indexOf("postal_code") >= 0) {
26644                 result.postalCode = component.short_name;
26645             } else if (component.types.indexOf("street_number") >= 0) {
26646                 result.streetNumber = component.short_name;
26647             } else if (component.types.indexOf("route") >= 0) {
26648                 result.streetName = component.short_name;
26649             } else if (component.types.indexOf("neighborhood") >= 0) {
26650                 result.city = component.short_name;
26651             } else if (component.types.indexOf("locality") >= 0) {
26652                 result.city = component.short_name;
26653             } else if (component.types.indexOf("sublocality") >= 0) {
26654                 result.district = component.short_name;
26655             } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26656                 result.stateOrProvince = component.short_name;
26657             } else if (component.types.indexOf("country") >= 0) {
26658                 result.country = component.short_name;
26659             }
26660         }
26661         
26662         result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26663         result.addressLine2 = "";
26664         return result;
26665     },
26666     
26667     setZoomLevel: function(zoom)
26668     {
26669         this.gMapContext.map.setZoom(zoom);
26670     },
26671     
26672     show: function()
26673     {
26674         if(!this.el){
26675             return;
26676         }
26677         
26678         this.el.show();
26679         
26680         this.resize();
26681         
26682         this.fireEvent('show', this);
26683     },
26684     
26685     hide: function()
26686     {
26687         if(!this.el){
26688             return;
26689         }
26690         
26691         this.el.hide();
26692         
26693         this.fireEvent('hide', this);
26694     }
26695     
26696 });
26697
26698 Roo.apply(Roo.bootstrap.LocationPicker, {
26699     
26700     OverlayView : function(map, options)
26701     {
26702         options = options || {};
26703         
26704         this.setMap(map);
26705     }
26706     
26707     
26708 });/*
26709  * - LGPL
26710  *
26711  * Alert
26712  * 
26713  */
26714
26715 /**
26716  * @class Roo.bootstrap.Alert
26717  * @extends Roo.bootstrap.Component
26718  * Bootstrap Alert class
26719  * @cfg {String} title The title of alert
26720  * @cfg {String} html The content of alert
26721  * @cfg {String} weight (  success | info | warning | danger )
26722  * @cfg {String} faicon font-awesomeicon
26723  * 
26724  * @constructor
26725  * Create a new alert
26726  * @param {Object} config The config object
26727  */
26728
26729
26730 Roo.bootstrap.Alert = function(config){
26731     Roo.bootstrap.Alert.superclass.constructor.call(this, config);
26732     
26733 };
26734
26735 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component,  {
26736     
26737     title: '',
26738     html: '',
26739     weight: false,
26740     faicon: false,
26741     
26742     getAutoCreate : function()
26743     {
26744         
26745         var cfg = {
26746             tag : 'div',
26747             cls : 'alert',
26748             cn : [
26749                 {
26750                     tag : 'i',
26751                     cls : 'roo-alert-icon'
26752                     
26753                 },
26754                 {
26755                     tag : 'b',
26756                     cls : 'roo-alert-title',
26757                     html : this.title
26758                 },
26759                 {
26760                     tag : 'span',
26761                     cls : 'roo-alert-text',
26762                     html : this.html
26763                 }
26764             ]
26765         };
26766         
26767         if(this.faicon){
26768             cfg.cn[0].cls += ' fa ' + this.faicon;
26769         }
26770         
26771         if(this.weight){
26772             cfg.cls += ' alert-' + this.weight;
26773         }
26774         
26775         return cfg;
26776     },
26777     
26778     initEvents: function() 
26779     {
26780         this.el.setVisibilityMode(Roo.Element.DISPLAY);
26781     },
26782     
26783     setTitle : function(str)
26784     {
26785         this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
26786     },
26787     
26788     setText : function(str)
26789     {
26790         this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
26791     },
26792     
26793     setWeight : function(weight)
26794     {
26795         if(this.weight){
26796             this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
26797         }
26798         
26799         this.weight = weight;
26800         
26801         this.el.select('.alert',true).first().addClass('alert-' + this.weight);
26802     },
26803     
26804     setIcon : function(icon)
26805     {
26806         if(this.faicon){
26807             this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
26808         }
26809         
26810         this.faicon = icon;
26811         
26812         this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
26813     },
26814     
26815     hide: function() 
26816     {
26817         this.el.hide();   
26818     },
26819     
26820     show: function() 
26821     {  
26822         this.el.show();   
26823     }
26824     
26825 });
26826
26827  
26828 /*
26829 * Licence: LGPL
26830 */
26831
26832 /**
26833  * @class Roo.bootstrap.UploadCropbox
26834  * @extends Roo.bootstrap.Component
26835  * Bootstrap UploadCropbox class
26836  * @cfg {String} emptyText show when image has been loaded
26837  * @cfg {String} rotateNotify show when image too small to rotate
26838  * @cfg {Number} errorTimeout default 3000
26839  * @cfg {Number} minWidth default 300
26840  * @cfg {Number} minHeight default 300
26841  * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
26842  * @cfg {Boolean} isDocument (true|false) default false
26843  * @cfg {String} url action url
26844  * @cfg {String} paramName default 'imageUpload'
26845  * @cfg {String} method default POST
26846  * @cfg {Boolean} loadMask (true|false) default true
26847  * @cfg {Boolean} loadingText default 'Loading...'
26848  * 
26849  * @constructor
26850  * Create a new UploadCropbox
26851  * @param {Object} config The config object
26852  */
26853
26854 Roo.bootstrap.UploadCropbox = function(config){
26855     Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
26856     
26857     this.addEvents({
26858         /**
26859          * @event beforeselectfile
26860          * Fire before select file
26861          * @param {Roo.bootstrap.UploadCropbox} this
26862          */
26863         "beforeselectfile" : true,
26864         /**
26865          * @event initial
26866          * Fire after initEvent
26867          * @param {Roo.bootstrap.UploadCropbox} this
26868          */
26869         "initial" : true,
26870         /**
26871          * @event crop
26872          * Fire after initEvent
26873          * @param {Roo.bootstrap.UploadCropbox} this
26874          * @param {String} data
26875          */
26876         "crop" : true,
26877         /**
26878          * @event prepare
26879          * Fire when preparing the file data
26880          * @param {Roo.bootstrap.UploadCropbox} this
26881          * @param {Object} file
26882          */
26883         "prepare" : true,
26884         /**
26885          * @event exception
26886          * Fire when get exception
26887          * @param {Roo.bootstrap.UploadCropbox} this
26888          * @param {XMLHttpRequest} xhr
26889          */
26890         "exception" : true,
26891         /**
26892          * @event beforeloadcanvas
26893          * Fire before load the canvas
26894          * @param {Roo.bootstrap.UploadCropbox} this
26895          * @param {String} src
26896          */
26897         "beforeloadcanvas" : true,
26898         /**
26899          * @event trash
26900          * Fire when trash image
26901          * @param {Roo.bootstrap.UploadCropbox} this
26902          */
26903         "trash" : true,
26904         /**
26905          * @event download
26906          * Fire when download the image
26907          * @param {Roo.bootstrap.UploadCropbox} this
26908          */
26909         "download" : true,
26910         /**
26911          * @event footerbuttonclick
26912          * Fire when footerbuttonclick
26913          * @param {Roo.bootstrap.UploadCropbox} this
26914          * @param {String} type
26915          */
26916         "footerbuttonclick" : true,
26917         /**
26918          * @event resize
26919          * Fire when resize
26920          * @param {Roo.bootstrap.UploadCropbox} this
26921          */
26922         "resize" : true,
26923         /**
26924          * @event rotate
26925          * Fire when rotate the image
26926          * @param {Roo.bootstrap.UploadCropbox} this
26927          * @param {String} pos
26928          */
26929         "rotate" : true,
26930         /**
26931          * @event inspect
26932          * Fire when inspect the file
26933          * @param {Roo.bootstrap.UploadCropbox} this
26934          * @param {Object} file
26935          */
26936         "inspect" : true,
26937         /**
26938          * @event upload
26939          * Fire when xhr upload the file
26940          * @param {Roo.bootstrap.UploadCropbox} this
26941          * @param {Object} data
26942          */
26943         "upload" : true,
26944         /**
26945          * @event arrange
26946          * Fire when arrange the file data
26947          * @param {Roo.bootstrap.UploadCropbox} this
26948          * @param {Object} formData
26949          */
26950         "arrange" : true
26951     });
26952     
26953     this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
26954 };
26955
26956 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component,  {
26957     
26958     emptyText : 'Click to upload image',
26959     rotateNotify : 'Image is too small to rotate',
26960     errorTimeout : 3000,
26961     scale : 0,
26962     baseScale : 1,
26963     rotate : 0,
26964     dragable : false,
26965     pinching : false,
26966     mouseX : 0,
26967     mouseY : 0,
26968     cropData : false,
26969     minWidth : 300,
26970     minHeight : 300,
26971     file : false,
26972     exif : {},
26973     baseRotate : 1,
26974     cropType : 'image/jpeg',
26975     buttons : false,
26976     canvasLoaded : false,
26977     isDocument : false,
26978     method : 'POST',
26979     paramName : 'imageUpload',
26980     loadMask : true,
26981     loadingText : 'Loading...',
26982     maskEl : false,
26983     
26984     getAutoCreate : function()
26985     {
26986         var cfg = {
26987             tag : 'div',
26988             cls : 'roo-upload-cropbox',
26989             cn : [
26990                 {
26991                     tag : 'input',
26992                     cls : 'roo-upload-cropbox-selector',
26993                     type : 'file'
26994                 },
26995                 {
26996                     tag : 'div',
26997                     cls : 'roo-upload-cropbox-body',
26998                     style : 'cursor:pointer',
26999                     cn : [
27000                         {
27001                             tag : 'div',
27002                             cls : 'roo-upload-cropbox-preview'
27003                         },
27004                         {
27005                             tag : 'div',
27006                             cls : 'roo-upload-cropbox-thumb'
27007                         },
27008                         {
27009                             tag : 'div',
27010                             cls : 'roo-upload-cropbox-empty-notify',
27011                             html : this.emptyText
27012                         },
27013                         {
27014                             tag : 'div',
27015                             cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27016                             html : this.rotateNotify
27017                         }
27018                     ]
27019                 },
27020                 {
27021                     tag : 'div',
27022                     cls : 'roo-upload-cropbox-footer',
27023                     cn : {
27024                         tag : 'div',
27025                         cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27026                         cn : []
27027                     }
27028                 }
27029             ]
27030         };
27031         
27032         return cfg;
27033     },
27034     
27035     onRender : function(ct, position)
27036     {
27037         Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27038         
27039         if (this.buttons.length) {
27040             
27041             Roo.each(this.buttons, function(bb) {
27042                 
27043                 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27044                 
27045                 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27046                 
27047             }, this);
27048         }
27049         
27050         if(this.loadMask){
27051             this.maskEl = this.el;
27052         }
27053     },
27054     
27055     initEvents : function()
27056     {
27057         this.urlAPI = (window.createObjectURL && window) || 
27058                                 (window.URL && URL.revokeObjectURL && URL) || 
27059                                 (window.webkitURL && webkitURL);
27060                         
27061         this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27062         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27063         
27064         this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27065         this.selectorEl.hide();
27066         
27067         this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27068         this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27069         
27070         this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27071         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27072         this.thumbEl.hide();
27073         
27074         this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27075         this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27076         
27077         this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27078         this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27079         this.errorEl.hide();
27080         
27081         this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27082         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27083         this.footerEl.hide();
27084         
27085         this.setThumbBoxSize();
27086         
27087         this.bind();
27088         
27089         this.resize();
27090         
27091         this.fireEvent('initial', this);
27092     },
27093
27094     bind : function()
27095     {
27096         var _this = this;
27097         
27098         window.addEventListener("resize", function() { _this.resize(); } );
27099         
27100         this.bodyEl.on('click', this.beforeSelectFile, this);
27101         
27102         if(Roo.isTouch){
27103             this.bodyEl.on('touchstart', this.onTouchStart, this);
27104             this.bodyEl.on('touchmove', this.onTouchMove, this);
27105             this.bodyEl.on('touchend', this.onTouchEnd, this);
27106         }
27107         
27108         if(!Roo.isTouch){
27109             this.bodyEl.on('mousedown', this.onMouseDown, this);
27110             this.bodyEl.on('mousemove', this.onMouseMove, this);
27111             var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27112             this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27113             Roo.get(document).on('mouseup', this.onMouseUp, this);
27114         }
27115         
27116         this.selectorEl.on('change', this.onFileSelected, this);
27117     },
27118     
27119     reset : function()
27120     {    
27121         this.scale = 0;
27122         this.baseScale = 1;
27123         this.rotate = 0;
27124         this.baseRotate = 1;
27125         this.dragable = false;
27126         this.pinching = false;
27127         this.mouseX = 0;
27128         this.mouseY = 0;
27129         this.cropData = false;
27130         this.notifyEl.dom.innerHTML = this.emptyText;
27131         
27132         this.selectorEl.dom.value = '';
27133         
27134     },
27135     
27136     resize : function()
27137     {
27138         if(this.fireEvent('resize', this) != false){
27139             this.setThumbBoxPosition();
27140             this.setCanvasPosition();
27141         }
27142     },
27143     
27144     onFooterButtonClick : function(e, el, o, type)
27145     {
27146         switch (type) {
27147             case 'rotate-left' :
27148                 this.onRotateLeft(e);
27149                 break;
27150             case 'rotate-right' :
27151                 this.onRotateRight(e);
27152                 break;
27153             case 'picture' :
27154                 this.beforeSelectFile(e);
27155                 break;
27156             case 'trash' :
27157                 this.trash(e);
27158                 break;
27159             case 'crop' :
27160                 this.crop(e);
27161                 break;
27162             case 'download' :
27163                 this.download(e);
27164                 break;
27165             default :
27166                 break;
27167         }
27168         
27169         this.fireEvent('footerbuttonclick', this, type);
27170     },
27171     
27172     beforeSelectFile : function(e)
27173     {
27174         e.preventDefault();
27175         
27176         if(this.fireEvent('beforeselectfile', this) != false){
27177             this.selectorEl.dom.click();
27178         }
27179     },
27180     
27181     onFileSelected : function(e)
27182     {
27183         e.preventDefault();
27184         
27185         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27186             return;
27187         }
27188         
27189         var file = this.selectorEl.dom.files[0];
27190         
27191         if(this.fireEvent('inspect', this, file) != false){
27192             this.prepare(file);
27193         }
27194         
27195     },
27196     
27197     trash : function(e)
27198     {
27199         this.fireEvent('trash', this);
27200     },
27201     
27202     download : function(e)
27203     {
27204         this.fireEvent('download', this);
27205     },
27206     
27207     loadCanvas : function(src)
27208     {   
27209         if(this.fireEvent('beforeloadcanvas', this, src) != false){
27210             
27211             this.reset();
27212             
27213             this.imageEl = document.createElement('img');
27214             
27215             var _this = this;
27216             
27217             this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27218             
27219             this.imageEl.src = src;
27220         }
27221     },
27222     
27223     onLoadCanvas : function()
27224     {   
27225         this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27226         this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27227         
27228         this.bodyEl.un('click', this.beforeSelectFile, this);
27229         
27230         this.notifyEl.hide();
27231         this.thumbEl.show();
27232         this.footerEl.show();
27233         
27234         this.baseRotateLevel();
27235         
27236         if(this.isDocument){
27237             this.setThumbBoxSize();
27238         }
27239         
27240         this.setThumbBoxPosition();
27241         
27242         this.baseScaleLevel();
27243         
27244         this.draw();
27245         
27246         this.resize();
27247         
27248         this.canvasLoaded = true;
27249         
27250         if(this.loadMask){
27251             this.maskEl.unmask();
27252         }
27253         
27254     },
27255     
27256     setCanvasPosition : function()
27257     {   
27258         if(!this.canvasEl){
27259             return;
27260         }
27261         
27262         var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27263         var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27264         
27265         this.previewEl.setLeft(pw);
27266         this.previewEl.setTop(ph);
27267         
27268     },
27269     
27270     onMouseDown : function(e)
27271     {   
27272         e.stopEvent();
27273         
27274         this.dragable = true;
27275         this.pinching = false;
27276         
27277         if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27278             this.dragable = false;
27279             return;
27280         }
27281         
27282         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27283         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27284         
27285     },
27286     
27287     onMouseMove : function(e)
27288     {   
27289         e.stopEvent();
27290         
27291         if(!this.canvasLoaded){
27292             return;
27293         }
27294         
27295         if (!this.dragable){
27296             return;
27297         }
27298         
27299         var minX = Math.ceil(this.thumbEl.getLeft(true));
27300         var minY = Math.ceil(this.thumbEl.getTop(true));
27301         
27302         var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27303         var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27304         
27305         var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27306         var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27307         
27308         x = x - this.mouseX;
27309         y = y - this.mouseY;
27310         
27311         var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27312         var bgY = Math.ceil(y + this.previewEl.getTop(true));
27313         
27314         bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27315         bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27316         
27317         this.previewEl.setLeft(bgX);
27318         this.previewEl.setTop(bgY);
27319         
27320         this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27321         this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27322     },
27323     
27324     onMouseUp : function(e)
27325     {   
27326         e.stopEvent();
27327         
27328         this.dragable = false;
27329     },
27330     
27331     onMouseWheel : function(e)
27332     {   
27333         e.stopEvent();
27334         
27335         this.startScale = this.scale;
27336         
27337         this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27338         
27339         if(!this.zoomable()){
27340             this.scale = this.startScale;
27341             return;
27342         }
27343         
27344         this.draw();
27345         
27346         return;
27347     },
27348     
27349     zoomable : function()
27350     {
27351         var minScale = this.thumbEl.getWidth() / this.minWidth;
27352         
27353         if(this.minWidth < this.minHeight){
27354             minScale = this.thumbEl.getHeight() / this.minHeight;
27355         }
27356         
27357         var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27358         var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27359         
27360         if(
27361                 this.isDocument &&
27362                 (this.rotate == 0 || this.rotate == 180) && 
27363                 (
27364                     width > this.imageEl.OriginWidth || 
27365                     height > this.imageEl.OriginHeight ||
27366                     (width < this.minWidth && height < this.minHeight)
27367                 )
27368         ){
27369             return false;
27370         }
27371         
27372         if(
27373                 this.isDocument &&
27374                 (this.rotate == 90 || this.rotate == 270) && 
27375                 (
27376                     width > this.imageEl.OriginWidth || 
27377                     height > this.imageEl.OriginHeight ||
27378                     (width < this.minHeight && height < this.minWidth)
27379                 )
27380         ){
27381             return false;
27382         }
27383         
27384         if(
27385                 !this.isDocument &&
27386                 (this.rotate == 0 || this.rotate == 180) && 
27387                 (
27388                     width < this.minWidth || 
27389                     width > this.imageEl.OriginWidth || 
27390                     height < this.minHeight || 
27391                     height > this.imageEl.OriginHeight
27392                 )
27393         ){
27394             return false;
27395         }
27396         
27397         if(
27398                 !this.isDocument &&
27399                 (this.rotate == 90 || this.rotate == 270) && 
27400                 (
27401                     width < this.minHeight || 
27402                     width > this.imageEl.OriginWidth || 
27403                     height < this.minWidth || 
27404                     height > this.imageEl.OriginHeight
27405                 )
27406         ){
27407             return false;
27408         }
27409         
27410         return true;
27411         
27412     },
27413     
27414     onRotateLeft : function(e)
27415     {   
27416         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27417             
27418             var minScale = this.thumbEl.getWidth() / this.minWidth;
27419             
27420             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27421             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27422             
27423             this.startScale = this.scale;
27424             
27425             while (this.getScaleLevel() < minScale){
27426             
27427                 this.scale = this.scale + 1;
27428                 
27429                 if(!this.zoomable()){
27430                     break;
27431                 }
27432                 
27433                 if(
27434                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27435                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27436                 ){
27437                     continue;
27438                 }
27439                 
27440                 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27441
27442                 this.draw();
27443                 
27444                 return;
27445             }
27446             
27447             this.scale = this.startScale;
27448             
27449             this.onRotateFail();
27450             
27451             return false;
27452         }
27453         
27454         this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27455
27456         if(this.isDocument){
27457             this.setThumbBoxSize();
27458             this.setThumbBoxPosition();
27459             this.setCanvasPosition();
27460         }
27461         
27462         this.draw();
27463         
27464         this.fireEvent('rotate', this, 'left');
27465         
27466     },
27467     
27468     onRotateRight : function(e)
27469     {
27470         if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27471             
27472             var minScale = this.thumbEl.getWidth() / this.minWidth;
27473         
27474             var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27475             var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27476             
27477             this.startScale = this.scale;
27478             
27479             while (this.getScaleLevel() < minScale){
27480             
27481                 this.scale = this.scale + 1;
27482                 
27483                 if(!this.zoomable()){
27484                     break;
27485                 }
27486                 
27487                 if(
27488                         Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27489                         Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27490                 ){
27491                     continue;
27492                 }
27493                 
27494                 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27495
27496                 this.draw();
27497                 
27498                 return;
27499             }
27500             
27501             this.scale = this.startScale;
27502             
27503             this.onRotateFail();
27504             
27505             return false;
27506         }
27507         
27508         this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27509
27510         if(this.isDocument){
27511             this.setThumbBoxSize();
27512             this.setThumbBoxPosition();
27513             this.setCanvasPosition();
27514         }
27515         
27516         this.draw();
27517         
27518         this.fireEvent('rotate', this, 'right');
27519     },
27520     
27521     onRotateFail : function()
27522     {
27523         this.errorEl.show(true);
27524         
27525         var _this = this;
27526         
27527         (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27528     },
27529     
27530     draw : function()
27531     {
27532         this.previewEl.dom.innerHTML = '';
27533         
27534         var canvasEl = document.createElement("canvas");
27535         
27536         var contextEl = canvasEl.getContext("2d");
27537         
27538         canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27539         canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27540         var center = this.imageEl.OriginWidth / 2;
27541         
27542         if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27543             canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27544             canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27545             center = this.imageEl.OriginHeight / 2;
27546         }
27547         
27548         contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27549         
27550         contextEl.translate(center, center);
27551         contextEl.rotate(this.rotate * Math.PI / 180);
27552
27553         contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27554         
27555         this.canvasEl = document.createElement("canvas");
27556         
27557         this.contextEl = this.canvasEl.getContext("2d");
27558         
27559         switch (this.rotate) {
27560             case 0 :
27561                 
27562                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27563                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27564                 
27565                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27566                 
27567                 break;
27568             case 90 : 
27569                 
27570                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27571                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27572                 
27573                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27574                     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);
27575                     break;
27576                 }
27577                 
27578                 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27579                 
27580                 break;
27581             case 180 :
27582                 
27583                 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27584                 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27585                 
27586                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27587                     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);
27588                     break;
27589                 }
27590                 
27591                 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);
27592                 
27593                 break;
27594             case 270 :
27595                 
27596                 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27597                 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27598         
27599                 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27600                     this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27601                     break;
27602                 }
27603                 
27604                 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);
27605                 
27606                 break;
27607             default : 
27608                 break;
27609         }
27610         
27611         this.previewEl.appendChild(this.canvasEl);
27612         
27613         this.setCanvasPosition();
27614     },
27615     
27616     crop : function()
27617     {
27618         if(!this.canvasLoaded){
27619             return;
27620         }
27621         
27622         var imageCanvas = document.createElement("canvas");
27623         
27624         var imageContext = imageCanvas.getContext("2d");
27625         
27626         imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27627         imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27628         
27629         var center = imageCanvas.width / 2;
27630         
27631         imageContext.translate(center, center);
27632         
27633         imageContext.rotate(this.rotate * Math.PI / 180);
27634         
27635         imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27636         
27637         var canvas = document.createElement("canvas");
27638         
27639         var context = canvas.getContext("2d");
27640                 
27641         canvas.width = this.minWidth;
27642         canvas.height = this.minHeight;
27643
27644         switch (this.rotate) {
27645             case 0 :
27646                 
27647                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27648                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27649                 
27650                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27651                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27652                 
27653                 var targetWidth = this.minWidth - 2 * x;
27654                 var targetHeight = this.minHeight - 2 * y;
27655                 
27656                 var scale = 1;
27657                 
27658                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27659                     scale = targetWidth / width;
27660                 }
27661                 
27662                 if(x > 0 && y == 0){
27663                     scale = targetHeight / height;
27664                 }
27665                 
27666                 if(x > 0 && y > 0){
27667                     scale = targetWidth / width;
27668                     
27669                     if(width < height){
27670                         scale = targetHeight / height;
27671                     }
27672                 }
27673                 
27674                 context.scale(scale, scale);
27675                 
27676                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27677                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27678
27679                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27680                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27681
27682                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27683                 
27684                 break;
27685             case 90 : 
27686                 
27687                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27688                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27689                 
27690                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27691                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27692                 
27693                 var targetWidth = this.minWidth - 2 * x;
27694                 var targetHeight = this.minHeight - 2 * y;
27695                 
27696                 var scale = 1;
27697                 
27698                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27699                     scale = targetWidth / width;
27700                 }
27701                 
27702                 if(x > 0 && y == 0){
27703                     scale = targetHeight / height;
27704                 }
27705                 
27706                 if(x > 0 && y > 0){
27707                     scale = targetWidth / width;
27708                     
27709                     if(width < height){
27710                         scale = targetHeight / height;
27711                     }
27712                 }
27713                 
27714                 context.scale(scale, scale);
27715                 
27716                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27717                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27718
27719                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27720                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27721                 
27722                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27723                 
27724                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27725                 
27726                 break;
27727             case 180 :
27728                 
27729                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27730                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27731                 
27732                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27733                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27734                 
27735                 var targetWidth = this.minWidth - 2 * x;
27736                 var targetHeight = this.minHeight - 2 * y;
27737                 
27738                 var scale = 1;
27739                 
27740                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27741                     scale = targetWidth / width;
27742                 }
27743                 
27744                 if(x > 0 && y == 0){
27745                     scale = targetHeight / height;
27746                 }
27747                 
27748                 if(x > 0 && y > 0){
27749                     scale = targetWidth / width;
27750                     
27751                     if(width < height){
27752                         scale = targetHeight / height;
27753                     }
27754                 }
27755                 
27756                 context.scale(scale, scale);
27757                 
27758                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27759                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27760
27761                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27762                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27763
27764                 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27765                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27766                 
27767                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27768                 
27769                 break;
27770             case 270 :
27771                 
27772                 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27773                 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27774                 
27775                 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27776                 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27777                 
27778                 var targetWidth = this.minWidth - 2 * x;
27779                 var targetHeight = this.minHeight - 2 * y;
27780                 
27781                 var scale = 1;
27782                 
27783                 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27784                     scale = targetWidth / width;
27785                 }
27786                 
27787                 if(x > 0 && y == 0){
27788                     scale = targetHeight / height;
27789                 }
27790                 
27791                 if(x > 0 && y > 0){
27792                     scale = targetWidth / width;
27793                     
27794                     if(width < height){
27795                         scale = targetHeight / height;
27796                     }
27797                 }
27798                 
27799                 context.scale(scale, scale);
27800                 
27801                 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27802                 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27803
27804                 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27805                 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27806                 
27807                 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
27808                 
27809                 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27810                 
27811                 break;
27812             default : 
27813                 break;
27814         }
27815         
27816         this.cropData = canvas.toDataURL(this.cropType);
27817         
27818         if(this.fireEvent('crop', this, this.cropData) !== false){
27819             this.process(this.file, this.cropData);
27820         }
27821         
27822         return;
27823         
27824     },
27825     
27826     setThumbBoxSize : function()
27827     {
27828         var width, height;
27829         
27830         if(this.isDocument && typeof(this.imageEl) != 'undefined'){
27831             width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
27832             height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
27833             
27834             this.minWidth = width;
27835             this.minHeight = height;
27836             
27837             if(this.rotate == 90 || this.rotate == 270){
27838                 this.minWidth = height;
27839                 this.minHeight = width;
27840             }
27841         }
27842         
27843         height = 300;
27844         width = Math.ceil(this.minWidth * height / this.minHeight);
27845         
27846         if(this.minWidth > this.minHeight){
27847             width = 300;
27848             height = Math.ceil(this.minHeight * width / this.minWidth);
27849         }
27850         
27851         this.thumbEl.setStyle({
27852             width : width + 'px',
27853             height : height + 'px'
27854         });
27855
27856         return;
27857             
27858     },
27859     
27860     setThumbBoxPosition : function()
27861     {
27862         var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
27863         var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
27864         
27865         this.thumbEl.setLeft(x);
27866         this.thumbEl.setTop(y);
27867         
27868     },
27869     
27870     baseRotateLevel : function()
27871     {
27872         this.baseRotate = 1;
27873         
27874         if(
27875                 typeof(this.exif) != 'undefined' &&
27876                 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
27877                 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
27878         ){
27879             this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
27880         }
27881         
27882         this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
27883         
27884     },
27885     
27886     baseScaleLevel : function()
27887     {
27888         var width, height;
27889         
27890         if(this.isDocument){
27891             
27892             if(this.baseRotate == 6 || this.baseRotate == 8){
27893             
27894                 height = this.thumbEl.getHeight();
27895                 this.baseScale = height / this.imageEl.OriginWidth;
27896
27897                 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
27898                     width = this.thumbEl.getWidth();
27899                     this.baseScale = width / this.imageEl.OriginHeight;
27900                 }
27901
27902                 return;
27903             }
27904
27905             height = this.thumbEl.getHeight();
27906             this.baseScale = height / this.imageEl.OriginHeight;
27907
27908             if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
27909                 width = this.thumbEl.getWidth();
27910                 this.baseScale = width / this.imageEl.OriginWidth;
27911             }
27912
27913             return;
27914         }
27915         
27916         if(this.baseRotate == 6 || this.baseRotate == 8){
27917             
27918             width = this.thumbEl.getHeight();
27919             this.baseScale = width / this.imageEl.OriginHeight;
27920             
27921             if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
27922                 height = this.thumbEl.getWidth();
27923                 this.baseScale = height / this.imageEl.OriginHeight;
27924             }
27925             
27926             if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27927                 height = this.thumbEl.getWidth();
27928                 this.baseScale = height / this.imageEl.OriginHeight;
27929                 
27930                 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
27931                     width = this.thumbEl.getHeight();
27932                     this.baseScale = width / this.imageEl.OriginWidth;
27933                 }
27934             }
27935             
27936             return;
27937         }
27938         
27939         width = this.thumbEl.getWidth();
27940         this.baseScale = width / this.imageEl.OriginWidth;
27941         
27942         if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
27943             height = this.thumbEl.getHeight();
27944             this.baseScale = height / this.imageEl.OriginHeight;
27945         }
27946         
27947         if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27948             
27949             height = this.thumbEl.getHeight();
27950             this.baseScale = height / this.imageEl.OriginHeight;
27951             
27952             if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
27953                 width = this.thumbEl.getWidth();
27954                 this.baseScale = width / this.imageEl.OriginWidth;
27955             }
27956             
27957         }
27958         
27959         return;
27960     },
27961     
27962     getScaleLevel : function()
27963     {
27964         return this.baseScale * Math.pow(1.1, this.scale);
27965     },
27966     
27967     onTouchStart : function(e)
27968     {
27969         if(!this.canvasLoaded){
27970             this.beforeSelectFile(e);
27971             return;
27972         }
27973         
27974         var touches = e.browserEvent.touches;
27975         
27976         if(!touches){
27977             return;
27978         }
27979         
27980         if(touches.length == 1){
27981             this.onMouseDown(e);
27982             return;
27983         }
27984         
27985         if(touches.length != 2){
27986             return;
27987         }
27988         
27989         var coords = [];
27990         
27991         for(var i = 0, finger; finger = touches[i]; i++){
27992             coords.push(finger.pageX, finger.pageY);
27993         }
27994         
27995         var x = Math.pow(coords[0] - coords[2], 2);
27996         var y = Math.pow(coords[1] - coords[3], 2);
27997         
27998         this.startDistance = Math.sqrt(x + y);
27999         
28000         this.startScale = this.scale;
28001         
28002         this.pinching = true;
28003         this.dragable = false;
28004         
28005     },
28006     
28007     onTouchMove : function(e)
28008     {
28009         if(!this.pinching && !this.dragable){
28010             return;
28011         }
28012         
28013         var touches = e.browserEvent.touches;
28014         
28015         if(!touches){
28016             return;
28017         }
28018         
28019         if(this.dragable){
28020             this.onMouseMove(e);
28021             return;
28022         }
28023         
28024         var coords = [];
28025         
28026         for(var i = 0, finger; finger = touches[i]; i++){
28027             coords.push(finger.pageX, finger.pageY);
28028         }
28029         
28030         var x = Math.pow(coords[0] - coords[2], 2);
28031         var y = Math.pow(coords[1] - coords[3], 2);
28032         
28033         this.endDistance = Math.sqrt(x + y);
28034         
28035         this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28036         
28037         if(!this.zoomable()){
28038             this.scale = this.startScale;
28039             return;
28040         }
28041         
28042         this.draw();
28043         
28044     },
28045     
28046     onTouchEnd : function(e)
28047     {
28048         this.pinching = false;
28049         this.dragable = false;
28050         
28051     },
28052     
28053     process : function(file, crop)
28054     {
28055         if(this.loadMask){
28056             this.maskEl.mask(this.loadingText);
28057         }
28058         
28059         this.xhr = new XMLHttpRequest();
28060         
28061         file.xhr = this.xhr;
28062
28063         this.xhr.open(this.method, this.url, true);
28064         
28065         var headers = {
28066             "Accept": "application/json",
28067             "Cache-Control": "no-cache",
28068             "X-Requested-With": "XMLHttpRequest"
28069         };
28070         
28071         for (var headerName in headers) {
28072             var headerValue = headers[headerName];
28073             if (headerValue) {
28074                 this.xhr.setRequestHeader(headerName, headerValue);
28075             }
28076         }
28077         
28078         var _this = this;
28079         
28080         this.xhr.onload = function()
28081         {
28082             _this.xhrOnLoad(_this.xhr);
28083         }
28084         
28085         this.xhr.onerror = function()
28086         {
28087             _this.xhrOnError(_this.xhr);
28088         }
28089         
28090         var formData = new FormData();
28091
28092         formData.append('returnHTML', 'NO');
28093         
28094         if(crop){
28095             formData.append('crop', crop);
28096         }
28097         
28098         if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28099             formData.append(this.paramName, file, file.name);
28100         }
28101         
28102         if(typeof(file.filename) != 'undefined'){
28103             formData.append('filename', file.filename);
28104         }
28105         
28106         if(typeof(file.mimetype) != 'undefined'){
28107             formData.append('mimetype', file.mimetype);
28108         }
28109         
28110         if(this.fireEvent('arrange', this, formData) != false){
28111             this.xhr.send(formData);
28112         };
28113     },
28114     
28115     xhrOnLoad : function(xhr)
28116     {
28117         if(this.loadMask){
28118             this.maskEl.unmask();
28119         }
28120         
28121         if (xhr.readyState !== 4) {
28122             this.fireEvent('exception', this, xhr);
28123             return;
28124         }
28125
28126         var response = Roo.decode(xhr.responseText);
28127         
28128         if(!response.success){
28129             this.fireEvent('exception', this, xhr);
28130             return;
28131         }
28132         
28133         var response = Roo.decode(xhr.responseText);
28134         
28135         this.fireEvent('upload', this, response);
28136         
28137     },
28138     
28139     xhrOnError : function()
28140     {
28141         if(this.loadMask){
28142             this.maskEl.unmask();
28143         }
28144         
28145         Roo.log('xhr on error');
28146         
28147         var response = Roo.decode(xhr.responseText);
28148           
28149         Roo.log(response);
28150         
28151     },
28152     
28153     prepare : function(file)
28154     {   
28155         if(this.loadMask){
28156             this.maskEl.mask(this.loadingText);
28157         }
28158         
28159         this.file = false;
28160         this.exif = {};
28161         
28162         if(typeof(file) === 'string'){
28163             this.loadCanvas(file);
28164             return;
28165         }
28166         
28167         if(!file || !this.urlAPI){
28168             return;
28169         }
28170         
28171         this.file = file;
28172         this.cropType = file.type;
28173         
28174         var _this = this;
28175         
28176         if(this.fireEvent('prepare', this, this.file) != false){
28177             
28178             var reader = new FileReader();
28179             
28180             reader.onload = function (e) {
28181                 if (e.target.error) {
28182                     Roo.log(e.target.error);
28183                     return;
28184                 }
28185                 
28186                 var buffer = e.target.result,
28187                     dataView = new DataView(buffer),
28188                     offset = 2,
28189                     maxOffset = dataView.byteLength - 4,
28190                     markerBytes,
28191                     markerLength;
28192                 
28193                 if (dataView.getUint16(0) === 0xffd8) {
28194                     while (offset < maxOffset) {
28195                         markerBytes = dataView.getUint16(offset);
28196                         
28197                         if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28198                             markerLength = dataView.getUint16(offset + 2) + 2;
28199                             if (offset + markerLength > dataView.byteLength) {
28200                                 Roo.log('Invalid meta data: Invalid segment size.');
28201                                 break;
28202                             }
28203                             
28204                             if(markerBytes == 0xffe1){
28205                                 _this.parseExifData(
28206                                     dataView,
28207                                     offset,
28208                                     markerLength
28209                                 );
28210                             }
28211                             
28212                             offset += markerLength;
28213                             
28214                             continue;
28215                         }
28216                         
28217                         break;
28218                     }
28219                     
28220                 }
28221                 
28222                 var url = _this.urlAPI.createObjectURL(_this.file);
28223                 
28224                 _this.loadCanvas(url);
28225                 
28226                 return;
28227             }
28228             
28229             reader.readAsArrayBuffer(this.file);
28230             
28231         }
28232         
28233     },
28234     
28235     parseExifData : function(dataView, offset, length)
28236     {
28237         var tiffOffset = offset + 10,
28238             littleEndian,
28239             dirOffset;
28240     
28241         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28242             // No Exif data, might be XMP data instead
28243             return;
28244         }
28245         
28246         // Check for the ASCII code for "Exif" (0x45786966):
28247         if (dataView.getUint32(offset + 4) !== 0x45786966) {
28248             // No Exif data, might be XMP data instead
28249             return;
28250         }
28251         if (tiffOffset + 8 > dataView.byteLength) {
28252             Roo.log('Invalid Exif data: Invalid segment size.');
28253             return;
28254         }
28255         // Check for the two null bytes:
28256         if (dataView.getUint16(offset + 8) !== 0x0000) {
28257             Roo.log('Invalid Exif data: Missing byte alignment offset.');
28258             return;
28259         }
28260         // Check the byte alignment:
28261         switch (dataView.getUint16(tiffOffset)) {
28262         case 0x4949:
28263             littleEndian = true;
28264             break;
28265         case 0x4D4D:
28266             littleEndian = false;
28267             break;
28268         default:
28269             Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28270             return;
28271         }
28272         // Check for the TIFF tag marker (0x002A):
28273         if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28274             Roo.log('Invalid Exif data: Missing TIFF marker.');
28275             return;
28276         }
28277         // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28278         dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28279         
28280         this.parseExifTags(
28281             dataView,
28282             tiffOffset,
28283             tiffOffset + dirOffset,
28284             littleEndian
28285         );
28286     },
28287     
28288     parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28289     {
28290         var tagsNumber,
28291             dirEndOffset,
28292             i;
28293         if (dirOffset + 6 > dataView.byteLength) {
28294             Roo.log('Invalid Exif data: Invalid directory offset.');
28295             return;
28296         }
28297         tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28298         dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28299         if (dirEndOffset + 4 > dataView.byteLength) {
28300             Roo.log('Invalid Exif data: Invalid directory size.');
28301             return;
28302         }
28303         for (i = 0; i < tagsNumber; i += 1) {
28304             this.parseExifTag(
28305                 dataView,
28306                 tiffOffset,
28307                 dirOffset + 2 + 12 * i, // tag offset
28308                 littleEndian
28309             );
28310         }
28311         // Return the offset to the next directory:
28312         return dataView.getUint32(dirEndOffset, littleEndian);
28313     },
28314     
28315     parseExifTag : function (dataView, tiffOffset, offset, littleEndian) 
28316     {
28317         var tag = dataView.getUint16(offset, littleEndian);
28318         
28319         this.exif[tag] = this.getExifValue(
28320             dataView,
28321             tiffOffset,
28322             offset,
28323             dataView.getUint16(offset + 2, littleEndian), // tag type
28324             dataView.getUint32(offset + 4, littleEndian), // tag length
28325             littleEndian
28326         );
28327     },
28328     
28329     getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28330     {
28331         var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28332             tagSize,
28333             dataOffset,
28334             values,
28335             i,
28336             str,
28337             c;
28338     
28339         if (!tagType) {
28340             Roo.log('Invalid Exif data: Invalid tag type.');
28341             return;
28342         }
28343         
28344         tagSize = tagType.size * length;
28345         // Determine if the value is contained in the dataOffset bytes,
28346         // or if the value at the dataOffset is a pointer to the actual data:
28347         dataOffset = tagSize > 4 ?
28348                 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28349         if (dataOffset + tagSize > dataView.byteLength) {
28350             Roo.log('Invalid Exif data: Invalid data offset.');
28351             return;
28352         }
28353         if (length === 1) {
28354             return tagType.getValue(dataView, dataOffset, littleEndian);
28355         }
28356         values = [];
28357         for (i = 0; i < length; i += 1) {
28358             values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28359         }
28360         
28361         if (tagType.ascii) {
28362             str = '';
28363             // Concatenate the chars:
28364             for (i = 0; i < values.length; i += 1) {
28365                 c = values[i];
28366                 // Ignore the terminating NULL byte(s):
28367                 if (c === '\u0000') {
28368                     break;
28369                 }
28370                 str += c;
28371             }
28372             return str;
28373         }
28374         return values;
28375     }
28376     
28377 });
28378
28379 Roo.apply(Roo.bootstrap.UploadCropbox, {
28380     tags : {
28381         'Orientation': 0x0112
28382     },
28383     
28384     Orientation: {
28385             1: 0, //'top-left',
28386 //            2: 'top-right',
28387             3: 180, //'bottom-right',
28388 //            4: 'bottom-left',
28389 //            5: 'left-top',
28390             6: 90, //'right-top',
28391 //            7: 'right-bottom',
28392             8: 270 //'left-bottom'
28393     },
28394     
28395     exifTagTypes : {
28396         // byte, 8-bit unsigned int:
28397         1: {
28398             getValue: function (dataView, dataOffset) {
28399                 return dataView.getUint8(dataOffset);
28400             },
28401             size: 1
28402         },
28403         // ascii, 8-bit byte:
28404         2: {
28405             getValue: function (dataView, dataOffset) {
28406                 return String.fromCharCode(dataView.getUint8(dataOffset));
28407             },
28408             size: 1,
28409             ascii: true
28410         },
28411         // short, 16 bit int:
28412         3: {
28413             getValue: function (dataView, dataOffset, littleEndian) {
28414                 return dataView.getUint16(dataOffset, littleEndian);
28415             },
28416             size: 2
28417         },
28418         // long, 32 bit int:
28419         4: {
28420             getValue: function (dataView, dataOffset, littleEndian) {
28421                 return dataView.getUint32(dataOffset, littleEndian);
28422             },
28423             size: 4
28424         },
28425         // rational = two long values, first is numerator, second is denominator:
28426         5: {
28427             getValue: function (dataView, dataOffset, littleEndian) {
28428                 return dataView.getUint32(dataOffset, littleEndian) /
28429                     dataView.getUint32(dataOffset + 4, littleEndian);
28430             },
28431             size: 8
28432         },
28433         // slong, 32 bit signed int:
28434         9: {
28435             getValue: function (dataView, dataOffset, littleEndian) {
28436                 return dataView.getInt32(dataOffset, littleEndian);
28437             },
28438             size: 4
28439         },
28440         // srational, two slongs, first is numerator, second is denominator:
28441         10: {
28442             getValue: function (dataView, dataOffset, littleEndian) {
28443                 return dataView.getInt32(dataOffset, littleEndian) /
28444                     dataView.getInt32(dataOffset + 4, littleEndian);
28445             },
28446             size: 8
28447         }
28448     },
28449     
28450     footer : {
28451         STANDARD : [
28452             {
28453                 tag : 'div',
28454                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28455                 action : 'rotate-left',
28456                 cn : [
28457                     {
28458                         tag : 'button',
28459                         cls : 'btn btn-default',
28460                         html : '<i class="fa fa-undo"></i>'
28461                     }
28462                 ]
28463             },
28464             {
28465                 tag : 'div',
28466                 cls : 'btn-group roo-upload-cropbox-picture',
28467                 action : 'picture',
28468                 cn : [
28469                     {
28470                         tag : 'button',
28471                         cls : 'btn btn-default',
28472                         html : '<i class="fa fa-picture-o"></i>'
28473                     }
28474                 ]
28475             },
28476             {
28477                 tag : 'div',
28478                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28479                 action : 'rotate-right',
28480                 cn : [
28481                     {
28482                         tag : 'button',
28483                         cls : 'btn btn-default',
28484                         html : '<i class="fa fa-repeat"></i>'
28485                     }
28486                 ]
28487             }
28488         ],
28489         DOCUMENT : [
28490             {
28491                 tag : 'div',
28492                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28493                 action : 'rotate-left',
28494                 cn : [
28495                     {
28496                         tag : 'button',
28497                         cls : 'btn btn-default',
28498                         html : '<i class="fa fa-undo"></i>'
28499                     }
28500                 ]
28501             },
28502             {
28503                 tag : 'div',
28504                 cls : 'btn-group roo-upload-cropbox-download',
28505                 action : 'download',
28506                 cn : [
28507                     {
28508                         tag : 'button',
28509                         cls : 'btn btn-default',
28510                         html : '<i class="fa fa-download"></i>'
28511                     }
28512                 ]
28513             },
28514             {
28515                 tag : 'div',
28516                 cls : 'btn-group roo-upload-cropbox-crop',
28517                 action : 'crop',
28518                 cn : [
28519                     {
28520                         tag : 'button',
28521                         cls : 'btn btn-default',
28522                         html : '<i class="fa fa-crop"></i>'
28523                     }
28524                 ]
28525             },
28526             {
28527                 tag : 'div',
28528                 cls : 'btn-group roo-upload-cropbox-trash',
28529                 action : 'trash',
28530                 cn : [
28531                     {
28532                         tag : 'button',
28533                         cls : 'btn btn-default',
28534                         html : '<i class="fa fa-trash"></i>'
28535                     }
28536                 ]
28537             },
28538             {
28539                 tag : 'div',
28540                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28541                 action : 'rotate-right',
28542                 cn : [
28543                     {
28544                         tag : 'button',
28545                         cls : 'btn btn-default',
28546                         html : '<i class="fa fa-repeat"></i>'
28547                     }
28548                 ]
28549             }
28550         ],
28551         ROTATOR : [
28552             {
28553                 tag : 'div',
28554                 cls : 'btn-group roo-upload-cropbox-rotate-left',
28555                 action : 'rotate-left',
28556                 cn : [
28557                     {
28558                         tag : 'button',
28559                         cls : 'btn btn-default',
28560                         html : '<i class="fa fa-undo"></i>'
28561                     }
28562                 ]
28563             },
28564             {
28565                 tag : 'div',
28566                 cls : 'btn-group roo-upload-cropbox-rotate-right',
28567                 action : 'rotate-right',
28568                 cn : [
28569                     {
28570                         tag : 'button',
28571                         cls : 'btn btn-default',
28572                         html : '<i class="fa fa-repeat"></i>'
28573                     }
28574                 ]
28575             }
28576         ]
28577     }
28578 });
28579
28580 /*
28581 * Licence: LGPL
28582 */
28583
28584 /**
28585  * @class Roo.bootstrap.DocumentManager
28586  * @extends Roo.bootstrap.Component
28587  * Bootstrap DocumentManager class
28588  * @cfg {String} paramName default 'imageUpload'
28589  * @cfg {String} toolTipName default 'filename'
28590  * @cfg {String} method default POST
28591  * @cfg {String} url action url
28592  * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28593  * @cfg {Boolean} multiple multiple upload default true
28594  * @cfg {Number} thumbSize default 300
28595  * @cfg {String} fieldLabel
28596  * @cfg {Number} labelWidth default 4
28597  * @cfg {String} labelAlign (left|top) default left
28598  * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28599 * @cfg {Number} labellg set the width of label (1-12)
28600  * @cfg {Number} labelmd set the width of label (1-12)
28601  * @cfg {Number} labelsm set the width of label (1-12)
28602  * @cfg {Number} labelxs set the width of label (1-12)
28603  * 
28604  * @constructor
28605  * Create a new DocumentManager
28606  * @param {Object} config The config object
28607  */
28608
28609 Roo.bootstrap.DocumentManager = function(config){
28610     Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28611     
28612     this.files = [];
28613     this.delegates = [];
28614     
28615     this.addEvents({
28616         /**
28617          * @event initial
28618          * Fire when initial the DocumentManager
28619          * @param {Roo.bootstrap.DocumentManager} this
28620          */
28621         "initial" : true,
28622         /**
28623          * @event inspect
28624          * inspect selected file
28625          * @param {Roo.bootstrap.DocumentManager} this
28626          * @param {File} file
28627          */
28628         "inspect" : true,
28629         /**
28630          * @event exception
28631          * Fire when xhr load exception
28632          * @param {Roo.bootstrap.DocumentManager} this
28633          * @param {XMLHttpRequest} xhr
28634          */
28635         "exception" : true,
28636         /**
28637          * @event afterupload
28638          * Fire when xhr load exception
28639          * @param {Roo.bootstrap.DocumentManager} this
28640          * @param {XMLHttpRequest} xhr
28641          */
28642         "afterupload" : true,
28643         /**
28644          * @event prepare
28645          * prepare the form data
28646          * @param {Roo.bootstrap.DocumentManager} this
28647          * @param {Object} formData
28648          */
28649         "prepare" : true,
28650         /**
28651          * @event remove
28652          * Fire when remove the file
28653          * @param {Roo.bootstrap.DocumentManager} this
28654          * @param {Object} file
28655          */
28656         "remove" : true,
28657         /**
28658          * @event refresh
28659          * Fire after refresh the file
28660          * @param {Roo.bootstrap.DocumentManager} this
28661          */
28662         "refresh" : true,
28663         /**
28664          * @event click
28665          * Fire after click the image
28666          * @param {Roo.bootstrap.DocumentManager} this
28667          * @param {Object} file
28668          */
28669         "click" : true,
28670         /**
28671          * @event edit
28672          * Fire when upload a image and editable set to true
28673          * @param {Roo.bootstrap.DocumentManager} this
28674          * @param {Object} file
28675          */
28676         "edit" : true,
28677         /**
28678          * @event beforeselectfile
28679          * Fire before select file
28680          * @param {Roo.bootstrap.DocumentManager} this
28681          */
28682         "beforeselectfile" : true,
28683         /**
28684          * @event process
28685          * Fire before process file
28686          * @param {Roo.bootstrap.DocumentManager} this
28687          * @param {Object} file
28688          */
28689         "process" : true,
28690         /**
28691          * @event previewrendered
28692          * Fire when preview rendered
28693          * @param {Roo.bootstrap.DocumentManager} this
28694          * @param {Object} file
28695          */
28696         "previewrendered" : true
28697         
28698     });
28699 };
28700
28701 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component,  {
28702     
28703     boxes : 0,
28704     inputName : '',
28705     thumbSize : 300,
28706     multiple : true,
28707     files : false,
28708     method : 'POST',
28709     url : '',
28710     paramName : 'imageUpload',
28711     toolTipName : 'filename',
28712     fieldLabel : '',
28713     labelWidth : 4,
28714     labelAlign : 'left',
28715     editable : true,
28716     delegates : false,
28717     xhr : false, 
28718     
28719     labellg : 0,
28720     labelmd : 0,
28721     labelsm : 0,
28722     labelxs : 0,
28723     
28724     getAutoCreate : function()
28725     {   
28726         var managerWidget = {
28727             tag : 'div',
28728             cls : 'roo-document-manager',
28729             cn : [
28730                 {
28731                     tag : 'input',
28732                     cls : 'roo-document-manager-selector',
28733                     type : 'file'
28734                 },
28735                 {
28736                     tag : 'div',
28737                     cls : 'roo-document-manager-uploader',
28738                     cn : [
28739                         {
28740                             tag : 'div',
28741                             cls : 'roo-document-manager-upload-btn',
28742                             html : '<i class="fa fa-plus"></i>'
28743                         }
28744                     ]
28745                     
28746                 }
28747             ]
28748         };
28749         
28750         var content = [
28751             {
28752                 tag : 'div',
28753                 cls : 'column col-md-12',
28754                 cn : managerWidget
28755             }
28756         ];
28757         
28758         if(this.fieldLabel.length){
28759             
28760             content = [
28761                 {
28762                     tag : 'div',
28763                     cls : 'column col-md-12',
28764                     html : this.fieldLabel
28765                 },
28766                 {
28767                     tag : 'div',
28768                     cls : 'column col-md-12',
28769                     cn : managerWidget
28770                 }
28771             ];
28772
28773             if(this.labelAlign == 'left'){
28774                 content = [
28775                     {
28776                         tag : 'div',
28777                         cls : 'column',
28778                         html : this.fieldLabel
28779                     },
28780                     {
28781                         tag : 'div',
28782                         cls : 'column',
28783                         cn : managerWidget
28784                     }
28785                 ];
28786                 
28787                 if(this.labelWidth > 12){
28788                     content[0].style = "width: " + this.labelWidth + 'px';
28789                 }
28790
28791                 if(this.labelWidth < 13 && this.labelmd == 0){
28792                     this.labelmd = this.labelWidth;
28793                 }
28794
28795                 if(this.labellg > 0){
28796                     content[0].cls += ' col-lg-' + this.labellg;
28797                     content[1].cls += ' col-lg-' + (12 - this.labellg);
28798                 }
28799
28800                 if(this.labelmd > 0){
28801                     content[0].cls += ' col-md-' + this.labelmd;
28802                     content[1].cls += ' col-md-' + (12 - this.labelmd);
28803                 }
28804
28805                 if(this.labelsm > 0){
28806                     content[0].cls += ' col-sm-' + this.labelsm;
28807                     content[1].cls += ' col-sm-' + (12 - this.labelsm);
28808                 }
28809
28810                 if(this.labelxs > 0){
28811                     content[0].cls += ' col-xs-' + this.labelxs;
28812                     content[1].cls += ' col-xs-' + (12 - this.labelxs);
28813                 }
28814                 
28815             }
28816         }
28817         
28818         var cfg = {
28819             tag : 'div',
28820             cls : 'row clearfix',
28821             cn : content
28822         };
28823         
28824         return cfg;
28825         
28826     },
28827     
28828     initEvents : function()
28829     {
28830         this.managerEl = this.el.select('.roo-document-manager', true).first();
28831         this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28832         
28833         this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
28834         this.selectorEl.hide();
28835         
28836         if(this.multiple){
28837             this.selectorEl.attr('multiple', 'multiple');
28838         }
28839         
28840         this.selectorEl.on('change', this.onFileSelected, this);
28841         
28842         this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
28843         this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
28844         
28845         this.uploader.on('click', this.onUploaderClick, this);
28846         
28847         this.renderProgressDialog();
28848         
28849         var _this = this;
28850         
28851         window.addEventListener("resize", function() { _this.refresh(); } );
28852         
28853         this.fireEvent('initial', this);
28854     },
28855     
28856     renderProgressDialog : function()
28857     {
28858         var _this = this;
28859         
28860         this.progressDialog = new Roo.bootstrap.Modal({
28861             cls : 'roo-document-manager-progress-dialog',
28862             allow_close : false,
28863             title : '',
28864             buttons : [
28865                 {
28866                     name  :'cancel',
28867                     weight : 'danger',
28868                     html : 'Cancel'
28869                 }
28870             ], 
28871             listeners : { 
28872                 btnclick : function() {
28873                     _this.uploadCancel();
28874                     this.hide();
28875                 }
28876             }
28877         });
28878          
28879         this.progressDialog.render(Roo.get(document.body));
28880          
28881         this.progress = new Roo.bootstrap.Progress({
28882             cls : 'roo-document-manager-progress',
28883             active : true,
28884             striped : true
28885         });
28886         
28887         this.progress.render(this.progressDialog.getChildContainer());
28888         
28889         this.progressBar = new Roo.bootstrap.ProgressBar({
28890             cls : 'roo-document-manager-progress-bar',
28891             aria_valuenow : 0,
28892             aria_valuemin : 0,
28893             aria_valuemax : 12,
28894             panel : 'success'
28895         });
28896         
28897         this.progressBar.render(this.progress.getChildContainer());
28898     },
28899     
28900     onUploaderClick : function(e)
28901     {
28902         e.preventDefault();
28903      
28904         if(this.fireEvent('beforeselectfile', this) != false){
28905             this.selectorEl.dom.click();
28906         }
28907         
28908     },
28909     
28910     onFileSelected : function(e)
28911     {
28912         e.preventDefault();
28913         
28914         if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
28915             return;
28916         }
28917         
28918         Roo.each(this.selectorEl.dom.files, function(file){
28919             if(this.fireEvent('inspect', this, file) != false){
28920                 this.files.push(file);
28921             }
28922         }, this);
28923         
28924         this.queue();
28925         
28926     },
28927     
28928     queue : function()
28929     {
28930         this.selectorEl.dom.value = '';
28931         
28932         if(!this.files || !this.files.length){
28933             return;
28934         }
28935         
28936         if(this.boxes > 0 && this.files.length > this.boxes){
28937             this.files = this.files.slice(0, this.boxes);
28938         }
28939         
28940         this.uploader.show();
28941         
28942         if(this.boxes > 0 && this.files.length > this.boxes - 1){
28943             this.uploader.hide();
28944         }
28945         
28946         var _this = this;
28947         
28948         var files = [];
28949         
28950         var docs = [];
28951         
28952         Roo.each(this.files, function(file){
28953             
28954             if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
28955                 var f = this.renderPreview(file);
28956                 files.push(f);
28957                 return;
28958             }
28959             
28960             if(file.type.indexOf('image') != -1){
28961                 this.delegates.push(
28962                     (function(){
28963                         _this.process(file);
28964                     }).createDelegate(this)
28965                 );
28966         
28967                 return;
28968             }
28969             
28970             docs.push(
28971                 (function(){
28972                     _this.process(file);
28973                 }).createDelegate(this)
28974             );
28975             
28976         }, this);
28977         
28978         this.files = files;
28979         
28980         this.delegates = this.delegates.concat(docs);
28981         
28982         if(!this.delegates.length){
28983             this.refresh();
28984             return;
28985         }
28986         
28987         this.progressBar.aria_valuemax = this.delegates.length;
28988         
28989         this.arrange();
28990         
28991         return;
28992     },
28993     
28994     arrange : function()
28995     {
28996         if(!this.delegates.length){
28997             this.progressDialog.hide();
28998             this.refresh();
28999             return;
29000         }
29001         
29002         var delegate = this.delegates.shift();
29003         
29004         this.progressDialog.show();
29005         
29006         this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29007         
29008         this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29009         
29010         delegate();
29011     },
29012     
29013     refresh : function()
29014     {
29015         this.uploader.show();
29016         
29017         if(this.boxes > 0 && this.files.length > this.boxes - 1){
29018             this.uploader.hide();
29019         }
29020         
29021         Roo.isTouch ? this.closable(false) : this.closable(true);
29022         
29023         this.fireEvent('refresh', this);
29024     },
29025     
29026     onRemove : function(e, el, o)
29027     {
29028         e.preventDefault();
29029         
29030         this.fireEvent('remove', this, o);
29031         
29032     },
29033     
29034     remove : function(o)
29035     {
29036         var files = [];
29037         
29038         Roo.each(this.files, function(file){
29039             if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29040                 files.push(file);
29041                 return;
29042             }
29043
29044             o.target.remove();
29045
29046         }, this);
29047         
29048         this.files = files;
29049         
29050         this.refresh();
29051     },
29052     
29053     clear : function()
29054     {
29055         Roo.each(this.files, function(file){
29056             if(!file.target){
29057                 return;
29058             }
29059             
29060             file.target.remove();
29061
29062         }, this);
29063         
29064         this.files = [];
29065         
29066         this.refresh();
29067     },
29068     
29069     onClick : function(e, el, o)
29070     {
29071         e.preventDefault();
29072         
29073         this.fireEvent('click', this, o);
29074         
29075     },
29076     
29077     closable : function(closable)
29078     {
29079         Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29080             
29081             el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29082             
29083             if(closable){
29084                 el.show();
29085                 return;
29086             }
29087             
29088             el.hide();
29089             
29090         }, this);
29091     },
29092     
29093     xhrOnLoad : function(xhr)
29094     {
29095         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29096             el.remove();
29097         }, this);
29098         
29099         if (xhr.readyState !== 4) {
29100             this.arrange();
29101             this.fireEvent('exception', this, xhr);
29102             return;
29103         }
29104
29105         var response = Roo.decode(xhr.responseText);
29106         
29107         if(!response.success){
29108             this.arrange();
29109             this.fireEvent('exception', this, xhr);
29110             return;
29111         }
29112         
29113         var file = this.renderPreview(response.data);
29114         
29115         this.files.push(file);
29116         
29117         this.arrange();
29118         
29119         this.fireEvent('afterupload', this, xhr);
29120         
29121     },
29122     
29123     xhrOnError : function(xhr)
29124     {
29125         Roo.log('xhr on error');
29126         
29127         var response = Roo.decode(xhr.responseText);
29128           
29129         Roo.log(response);
29130         
29131         this.arrange();
29132     },
29133     
29134     process : function(file)
29135     {
29136         if(this.fireEvent('process', this, file) !== false){
29137             if(this.editable && file.type.indexOf('image') != -1){
29138                 this.fireEvent('edit', this, file);
29139                 return;
29140             }
29141
29142             this.uploadStart(file, false);
29143
29144             return;
29145         }
29146         
29147     },
29148     
29149     uploadStart : function(file, crop)
29150     {
29151         this.xhr = new XMLHttpRequest();
29152         
29153         if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29154             this.arrange();
29155             return;
29156         }
29157         
29158         file.xhr = this.xhr;
29159             
29160         this.managerEl.createChild({
29161             tag : 'div',
29162             cls : 'roo-document-manager-loading',
29163             cn : [
29164                 {
29165                     tag : 'div',
29166                     tooltip : file.name,
29167                     cls : 'roo-document-manager-thumb',
29168                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29169                 }
29170             ]
29171
29172         });
29173
29174         this.xhr.open(this.method, this.url, true);
29175         
29176         var headers = {
29177             "Accept": "application/json",
29178             "Cache-Control": "no-cache",
29179             "X-Requested-With": "XMLHttpRequest"
29180         };
29181         
29182         for (var headerName in headers) {
29183             var headerValue = headers[headerName];
29184             if (headerValue) {
29185                 this.xhr.setRequestHeader(headerName, headerValue);
29186             }
29187         }
29188         
29189         var _this = this;
29190         
29191         this.xhr.onload = function()
29192         {
29193             _this.xhrOnLoad(_this.xhr);
29194         }
29195         
29196         this.xhr.onerror = function()
29197         {
29198             _this.xhrOnError(_this.xhr);
29199         }
29200         
29201         var formData = new FormData();
29202
29203         formData.append('returnHTML', 'NO');
29204         
29205         if(crop){
29206             formData.append('crop', crop);
29207         }
29208         
29209         formData.append(this.paramName, file, file.name);
29210         
29211         var options = {
29212             file : file, 
29213             manually : false
29214         };
29215         
29216         if(this.fireEvent('prepare', this, formData, options) != false){
29217             
29218             if(options.manually){
29219                 return;
29220             }
29221             
29222             this.xhr.send(formData);
29223             return;
29224         };
29225         
29226         this.uploadCancel();
29227     },
29228     
29229     uploadCancel : function()
29230     {
29231         if (this.xhr) {
29232             this.xhr.abort();
29233         }
29234         
29235         this.delegates = [];
29236         
29237         Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29238             el.remove();
29239         }, this);
29240         
29241         this.arrange();
29242     },
29243     
29244     renderPreview : function(file)
29245     {
29246         if(typeof(file.target) != 'undefined' && file.target){
29247             return file;
29248         }
29249         
29250         var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29251         
29252         var previewEl = this.managerEl.createChild({
29253             tag : 'div',
29254             cls : 'roo-document-manager-preview',
29255             cn : [
29256                 {
29257                     tag : 'div',
29258                     tooltip : file[this.toolTipName],
29259                     cls : 'roo-document-manager-thumb',
29260                     html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29261                 },
29262                 {
29263                     tag : 'button',
29264                     cls : 'close',
29265                     html : '<i class="fa fa-times-circle"></i>'
29266                 }
29267             ]
29268         });
29269
29270         var close = previewEl.select('button.close', true).first();
29271
29272         close.on('click', this.onRemove, this, file);
29273
29274         file.target = previewEl;
29275
29276         var image = previewEl.select('img', true).first();
29277         
29278         var _this = this;
29279         
29280         image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29281         
29282         image.on('click', this.onClick, this, file);
29283         
29284         this.fireEvent('previewrendered', this, file);
29285         
29286         return file;
29287         
29288     },
29289     
29290     onPreviewLoad : function(file, image)
29291     {
29292         if(typeof(file.target) == 'undefined' || !file.target){
29293             return;
29294         }
29295         
29296         var width = image.dom.naturalWidth || image.dom.width;
29297         var height = image.dom.naturalHeight || image.dom.height;
29298         
29299         if(width > height){
29300             file.target.addClass('wide');
29301             return;
29302         }
29303         
29304         file.target.addClass('tall');
29305         return;
29306         
29307     },
29308     
29309     uploadFromSource : function(file, crop)
29310     {
29311         this.xhr = new XMLHttpRequest();
29312         
29313         this.managerEl.createChild({
29314             tag : 'div',
29315             cls : 'roo-document-manager-loading',
29316             cn : [
29317                 {
29318                     tag : 'div',
29319                     tooltip : file.name,
29320                     cls : 'roo-document-manager-thumb',
29321                     html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29322                 }
29323             ]
29324
29325         });
29326
29327         this.xhr.open(this.method, this.url, true);
29328         
29329         var headers = {
29330             "Accept": "application/json",
29331             "Cache-Control": "no-cache",
29332             "X-Requested-With": "XMLHttpRequest"
29333         };
29334         
29335         for (var headerName in headers) {
29336             var headerValue = headers[headerName];
29337             if (headerValue) {
29338                 this.xhr.setRequestHeader(headerName, headerValue);
29339             }
29340         }
29341         
29342         var _this = this;
29343         
29344         this.xhr.onload = function()
29345         {
29346             _this.xhrOnLoad(_this.xhr);
29347         }
29348         
29349         this.xhr.onerror = function()
29350         {
29351             _this.xhrOnError(_this.xhr);
29352         }
29353         
29354         var formData = new FormData();
29355
29356         formData.append('returnHTML', 'NO');
29357         
29358         formData.append('crop', crop);
29359         
29360         if(typeof(file.filename) != 'undefined'){
29361             formData.append('filename', file.filename);
29362         }
29363         
29364         if(typeof(file.mimetype) != 'undefined'){
29365             formData.append('mimetype', file.mimetype);
29366         }
29367         
29368         Roo.log(formData);
29369         
29370         if(this.fireEvent('prepare', this, formData) != false){
29371             this.xhr.send(formData);
29372         };
29373     }
29374 });
29375
29376 /*
29377 * Licence: LGPL
29378 */
29379
29380 /**
29381  * @class Roo.bootstrap.DocumentViewer
29382  * @extends Roo.bootstrap.Component
29383  * Bootstrap DocumentViewer class
29384  * @cfg {Boolean} showDownload (true|false) show download button (default true)
29385  * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29386  * 
29387  * @constructor
29388  * Create a new DocumentViewer
29389  * @param {Object} config The config object
29390  */
29391
29392 Roo.bootstrap.DocumentViewer = function(config){
29393     Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29394     
29395     this.addEvents({
29396         /**
29397          * @event initial
29398          * Fire after initEvent
29399          * @param {Roo.bootstrap.DocumentViewer} this
29400          */
29401         "initial" : true,
29402         /**
29403          * @event click
29404          * Fire after click
29405          * @param {Roo.bootstrap.DocumentViewer} this
29406          */
29407         "click" : true,
29408         /**
29409          * @event download
29410          * Fire after download button
29411          * @param {Roo.bootstrap.DocumentViewer} this
29412          */
29413         "download" : true,
29414         /**
29415          * @event trash
29416          * Fire after trash button
29417          * @param {Roo.bootstrap.DocumentViewer} this
29418          */
29419         "trash" : true
29420         
29421     });
29422 };
29423
29424 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component,  {
29425     
29426     showDownload : true,
29427     
29428     showTrash : true,
29429     
29430     getAutoCreate : function()
29431     {
29432         var cfg = {
29433             tag : 'div',
29434             cls : 'roo-document-viewer',
29435             cn : [
29436                 {
29437                     tag : 'div',
29438                     cls : 'roo-document-viewer-body',
29439                     cn : [
29440                         {
29441                             tag : 'div',
29442                             cls : 'roo-document-viewer-thumb',
29443                             cn : [
29444                                 {
29445                                     tag : 'img',
29446                                     cls : 'roo-document-viewer-image'
29447                                 }
29448                             ]
29449                         }
29450                     ]
29451                 },
29452                 {
29453                     tag : 'div',
29454                     cls : 'roo-document-viewer-footer',
29455                     cn : {
29456                         tag : 'div',
29457                         cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29458                         cn : [
29459                             {
29460                                 tag : 'div',
29461                                 cls : 'btn-group roo-document-viewer-download',
29462                                 cn : [
29463                                     {
29464                                         tag : 'button',
29465                                         cls : 'btn btn-default',
29466                                         html : '<i class="fa fa-download"></i>'
29467                                     }
29468                                 ]
29469                             },
29470                             {
29471                                 tag : 'div',
29472                                 cls : 'btn-group roo-document-viewer-trash',
29473                                 cn : [
29474                                     {
29475                                         tag : 'button',
29476                                         cls : 'btn btn-default',
29477                                         html : '<i class="fa fa-trash"></i>'
29478                                     }
29479                                 ]
29480                             }
29481                         ]
29482                     }
29483                 }
29484             ]
29485         };
29486         
29487         return cfg;
29488     },
29489     
29490     initEvents : function()
29491     {
29492         this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29493         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29494         
29495         this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29496         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29497         
29498         this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29499         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29500         
29501         this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29502         this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29503         
29504         this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29505         this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29506         
29507         this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29508         this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29509         
29510         this.bodyEl.on('click', this.onClick, this);
29511         this.downloadBtn.on('click', this.onDownload, this);
29512         this.trashBtn.on('click', this.onTrash, this);
29513         
29514         this.downloadBtn.hide();
29515         this.trashBtn.hide();
29516         
29517         if(this.showDownload){
29518             this.downloadBtn.show();
29519         }
29520         
29521         if(this.showTrash){
29522             this.trashBtn.show();
29523         }
29524         
29525         if(!this.showDownload && !this.showTrash) {
29526             this.footerEl.hide();
29527         }
29528         
29529     },
29530     
29531     initial : function()
29532     {
29533         this.fireEvent('initial', this);
29534         
29535     },
29536     
29537     onClick : function(e)
29538     {
29539         e.preventDefault();
29540         
29541         this.fireEvent('click', this);
29542     },
29543     
29544     onDownload : function(e)
29545     {
29546         e.preventDefault();
29547         
29548         this.fireEvent('download', this);
29549     },
29550     
29551     onTrash : function(e)
29552     {
29553         e.preventDefault();
29554         
29555         this.fireEvent('trash', this);
29556     }
29557     
29558 });
29559 /*
29560  * - LGPL
29561  *
29562  * nav progress bar
29563  * 
29564  */
29565
29566 /**
29567  * @class Roo.bootstrap.NavProgressBar
29568  * @extends Roo.bootstrap.Component
29569  * Bootstrap NavProgressBar class
29570  * 
29571  * @constructor
29572  * Create a new nav progress bar
29573  * @param {Object} config The config object
29574  */
29575
29576 Roo.bootstrap.NavProgressBar = function(config){
29577     Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29578
29579     this.bullets = this.bullets || [];
29580    
29581 //    Roo.bootstrap.NavProgressBar.register(this);
29582      this.addEvents({
29583         /**
29584              * @event changed
29585              * Fires when the active item changes
29586              * @param {Roo.bootstrap.NavProgressBar} this
29587              * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29588              * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item 
29589          */
29590         'changed': true
29591      });
29592     
29593 };
29594
29595 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component,  {
29596     
29597     bullets : [],
29598     barItems : [],
29599     
29600     getAutoCreate : function()
29601     {
29602         var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29603         
29604         cfg = {
29605             tag : 'div',
29606             cls : 'roo-navigation-bar-group',
29607             cn : [
29608                 {
29609                     tag : 'div',
29610                     cls : 'roo-navigation-top-bar'
29611                 },
29612                 {
29613                     tag : 'div',
29614                     cls : 'roo-navigation-bullets-bar',
29615                     cn : [
29616                         {
29617                             tag : 'ul',
29618                             cls : 'roo-navigation-bar'
29619                         }
29620                     ]
29621                 },
29622                 
29623                 {
29624                     tag : 'div',
29625                     cls : 'roo-navigation-bottom-bar'
29626                 }
29627             ]
29628             
29629         };
29630         
29631         return cfg;
29632         
29633     },
29634     
29635     initEvents: function() 
29636     {
29637         
29638     },
29639     
29640     onRender : function(ct, position) 
29641     {
29642         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29643         
29644         if(this.bullets.length){
29645             Roo.each(this.bullets, function(b){
29646                this.addItem(b);
29647             }, this);
29648         }
29649         
29650         this.format();
29651         
29652     },
29653     
29654     addItem : function(cfg)
29655     {
29656         var item = new Roo.bootstrap.NavProgressItem(cfg);
29657         
29658         item.parentId = this.id;
29659         item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29660         
29661         if(cfg.html){
29662             var top = new Roo.bootstrap.Element({
29663                 tag : 'div',
29664                 cls : 'roo-navigation-bar-text'
29665             });
29666             
29667             var bottom = new Roo.bootstrap.Element({
29668                 tag : 'div',
29669                 cls : 'roo-navigation-bar-text'
29670             });
29671             
29672             top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29673             bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29674             
29675             var topText = new Roo.bootstrap.Element({
29676                 tag : 'span',
29677                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29678             });
29679             
29680             var bottomText = new Roo.bootstrap.Element({
29681                 tag : 'span',
29682                 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29683             });
29684             
29685             topText.onRender(top.el, null);
29686             bottomText.onRender(bottom.el, null);
29687             
29688             item.topEl = top;
29689             item.bottomEl = bottom;
29690         }
29691         
29692         this.barItems.push(item);
29693         
29694         return item;
29695     },
29696     
29697     getActive : function()
29698     {
29699         var active = false;
29700         
29701         Roo.each(this.barItems, function(v){
29702             
29703             if (!v.isActive()) {
29704                 return;
29705             }
29706             
29707             active = v;
29708             return false;
29709             
29710         });
29711         
29712         return active;
29713     },
29714     
29715     setActiveItem : function(item)
29716     {
29717         var prev = false;
29718         
29719         Roo.each(this.barItems, function(v){
29720             if (v.rid == item.rid) {
29721                 return ;
29722             }
29723             
29724             if (v.isActive()) {
29725                 v.setActive(false);
29726                 prev = v;
29727             }
29728         });
29729
29730         item.setActive(true);
29731         
29732         this.fireEvent('changed', this, item, prev);
29733     },
29734     
29735     getBarItem: function(rid)
29736     {
29737         var ret = false;
29738         
29739         Roo.each(this.barItems, function(e) {
29740             if (e.rid != rid) {
29741                 return;
29742             }
29743             
29744             ret =  e;
29745             return false;
29746         });
29747         
29748         return ret;
29749     },
29750     
29751     indexOfItem : function(item)
29752     {
29753         var index = false;
29754         
29755         Roo.each(this.barItems, function(v, i){
29756             
29757             if (v.rid != item.rid) {
29758                 return;
29759             }
29760             
29761             index = i;
29762             return false
29763         });
29764         
29765         return index;
29766     },
29767     
29768     setActiveNext : function()
29769     {
29770         var i = this.indexOfItem(this.getActive());
29771         
29772         if (i > this.barItems.length) {
29773             return;
29774         }
29775         
29776         this.setActiveItem(this.barItems[i+1]);
29777     },
29778     
29779     setActivePrev : function()
29780     {
29781         var i = this.indexOfItem(this.getActive());
29782         
29783         if (i  < 1) {
29784             return;
29785         }
29786         
29787         this.setActiveItem(this.barItems[i-1]);
29788     },
29789     
29790     format : function()
29791     {
29792         if(!this.barItems.length){
29793             return;
29794         }
29795      
29796         var width = 100 / this.barItems.length;
29797         
29798         Roo.each(this.barItems, function(i){
29799             i.el.setStyle('width', width + '%');
29800             i.topEl.el.setStyle('width', width + '%');
29801             i.bottomEl.el.setStyle('width', width + '%');
29802         }, this);
29803         
29804     }
29805     
29806 });
29807 /*
29808  * - LGPL
29809  *
29810  * Nav Progress Item
29811  * 
29812  */
29813
29814 /**
29815  * @class Roo.bootstrap.NavProgressItem
29816  * @extends Roo.bootstrap.Component
29817  * Bootstrap NavProgressItem class
29818  * @cfg {String} rid the reference id
29819  * @cfg {Boolean} active (true|false) Is item active default false
29820  * @cfg {Boolean} disabled (true|false) Is item active default false
29821  * @cfg {String} html
29822  * @cfg {String} position (top|bottom) text position default bottom
29823  * @cfg {String} icon show icon instead of number
29824  * 
29825  * @constructor
29826  * Create a new NavProgressItem
29827  * @param {Object} config The config object
29828  */
29829 Roo.bootstrap.NavProgressItem = function(config){
29830     Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
29831     this.addEvents({
29832         // raw events
29833         /**
29834          * @event click
29835          * The raw click event for the entire grid.
29836          * @param {Roo.bootstrap.NavProgressItem} this
29837          * @param {Roo.EventObject} e
29838          */
29839         "click" : true
29840     });
29841    
29842 };
29843
29844 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component,  {
29845     
29846     rid : '',
29847     active : false,
29848     disabled : false,
29849     html : '',
29850     position : 'bottom',
29851     icon : false,
29852     
29853     getAutoCreate : function()
29854     {
29855         var iconCls = 'roo-navigation-bar-item-icon';
29856         
29857         iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
29858         
29859         var cfg = {
29860             tag: 'li',
29861             cls: 'roo-navigation-bar-item',
29862             cn : [
29863                 {
29864                     tag : 'i',
29865                     cls : iconCls
29866                 }
29867             ]
29868         };
29869         
29870         if(this.active){
29871             cfg.cls += ' active';
29872         }
29873         if(this.disabled){
29874             cfg.cls += ' disabled';
29875         }
29876         
29877         return cfg;
29878     },
29879     
29880     disable : function()
29881     {
29882         this.setDisabled(true);
29883     },
29884     
29885     enable : function()
29886     {
29887         this.setDisabled(false);
29888     },
29889     
29890     initEvents: function() 
29891     {
29892         this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
29893         
29894         this.iconEl.on('click', this.onClick, this);
29895     },
29896     
29897     onClick : function(e)
29898     {
29899         e.preventDefault();
29900         
29901         if(this.disabled){
29902             return;
29903         }
29904         
29905         if(this.fireEvent('click', this, e) === false){
29906             return;
29907         };
29908         
29909         this.parent().setActiveItem(this);
29910     },
29911     
29912     isActive: function () 
29913     {
29914         return this.active;
29915     },
29916     
29917     setActive : function(state)
29918     {
29919         if(this.active == state){
29920             return;
29921         }
29922         
29923         this.active = state;
29924         
29925         if (state) {
29926             this.el.addClass('active');
29927             return;
29928         }
29929         
29930         this.el.removeClass('active');
29931         
29932         return;
29933     },
29934     
29935     setDisabled : function(state)
29936     {
29937         if(this.disabled == state){
29938             return;
29939         }
29940         
29941         this.disabled = state;
29942         
29943         if (state) {
29944             this.el.addClass('disabled');
29945             return;
29946         }
29947         
29948         this.el.removeClass('disabled');
29949     },
29950     
29951     tooltipEl : function()
29952     {
29953         return this.el.select('.roo-navigation-bar-item-icon', true).first();;
29954     }
29955 });
29956  
29957
29958  /*
29959  * - LGPL
29960  *
29961  * FieldLabel
29962  * 
29963  */
29964
29965 /**
29966  * @class Roo.bootstrap.FieldLabel
29967  * @extends Roo.bootstrap.Component
29968  * Bootstrap FieldLabel class
29969  * @cfg {String} html contents of the element
29970  * @cfg {String} tag tag of the element default label
29971  * @cfg {String} cls class of the element
29972  * @cfg {String} target label target 
29973  * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
29974  * @cfg {String} invalidClass default "text-warning"
29975  * @cfg {String} validClass default "text-success"
29976  * @cfg {String} iconTooltip default "This field is required"
29977  * @cfg {String} indicatorpos (left|right) default left
29978  * 
29979  * @constructor
29980  * Create a new FieldLabel
29981  * @param {Object} config The config object
29982  */
29983
29984 Roo.bootstrap.FieldLabel = function(config){
29985     Roo.bootstrap.Element.superclass.constructor.call(this, config);
29986     
29987     this.addEvents({
29988             /**
29989              * @event invalid
29990              * Fires after the field has been marked as invalid.
29991              * @param {Roo.form.FieldLabel} this
29992              * @param {String} msg The validation message
29993              */
29994             invalid : true,
29995             /**
29996              * @event valid
29997              * Fires after the field has been validated with no errors.
29998              * @param {Roo.form.FieldLabel} this
29999              */
30000             valid : true
30001         });
30002 };
30003
30004 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component,  {
30005     
30006     tag: 'label',
30007     cls: '',
30008     html: '',
30009     target: '',
30010     allowBlank : true,
30011     invalidClass : 'has-warning',
30012     validClass : 'has-success',
30013     iconTooltip : 'This field is required',
30014     indicatorpos : 'left',
30015     
30016     getAutoCreate : function(){
30017         
30018         var cls = "";
30019         if (!this.allowBlank) {
30020             cls  = "visible";
30021         }
30022         
30023         var cfg = {
30024             tag : this.tag,
30025             cls : 'roo-bootstrap-field-label ' + this.cls,
30026             for : this.target,
30027             cn : [
30028                 {
30029                     tag : 'i',
30030                     cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30031                     tooltip : this.iconTooltip
30032                 },
30033                 {
30034                     tag : 'span',
30035                     html : this.html
30036                 }
30037             ] 
30038         };
30039         
30040         if(this.indicatorpos == 'right'){
30041             var cfg = {
30042                 tag : this.tag,
30043                 cls : 'roo-bootstrap-field-label ' + this.cls,
30044                 for : this.target,
30045                 cn : [
30046                     {
30047                         tag : 'span',
30048                         html : this.html
30049                     },
30050                     {
30051                         tag : 'i',
30052                         cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30053                         tooltip : this.iconTooltip
30054                     }
30055                 ] 
30056             };
30057         }
30058         
30059         return cfg;
30060     },
30061     
30062     initEvents: function() 
30063     {
30064         Roo.bootstrap.Element.superclass.initEvents.call(this);
30065         
30066         this.indicator = this.indicatorEl();
30067         
30068         if(this.indicator){
30069             this.indicator.removeClass('visible');
30070             this.indicator.addClass('invisible');
30071         }
30072         
30073         Roo.bootstrap.FieldLabel.register(this);
30074     },
30075     
30076     indicatorEl : function()
30077     {
30078         var indicator = this.el.select('i.roo-required-indicator',true).first();
30079         
30080         if(!indicator){
30081             return false;
30082         }
30083         
30084         return indicator;
30085         
30086     },
30087     
30088     /**
30089      * Mark this field as valid
30090      */
30091     markValid : function()
30092     {
30093         if(this.indicator){
30094             this.indicator.removeClass('visible');
30095             this.indicator.addClass('invisible');
30096         }
30097         
30098         this.el.removeClass(this.invalidClass);
30099         
30100         this.el.addClass(this.validClass);
30101         
30102         this.fireEvent('valid', this);
30103     },
30104     
30105     /**
30106      * Mark this field as invalid
30107      * @param {String} msg The validation message
30108      */
30109     markInvalid : function(msg)
30110     {
30111         if(this.indicator){
30112             this.indicator.removeClass('invisible');
30113             this.indicator.addClass('visible');
30114         }
30115         
30116         this.el.removeClass(this.validClass);
30117         
30118         this.el.addClass(this.invalidClass);
30119         
30120         this.fireEvent('invalid', this, msg);
30121     }
30122     
30123    
30124 });
30125
30126 Roo.apply(Roo.bootstrap.FieldLabel, {
30127     
30128     groups: {},
30129     
30130      /**
30131     * register a FieldLabel Group
30132     * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30133     */
30134     register : function(label)
30135     {
30136         if(this.groups.hasOwnProperty(label.target)){
30137             return;
30138         }
30139      
30140         this.groups[label.target] = label;
30141         
30142     },
30143     /**
30144     * fetch a FieldLabel Group based on the target
30145     * @param {string} target
30146     * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30147     */
30148     get: function(target) {
30149         if (typeof(this.groups[target]) == 'undefined') {
30150             return false;
30151         }
30152         
30153         return this.groups[target] ;
30154     }
30155 });
30156
30157  
30158
30159  /*
30160  * - LGPL
30161  *
30162  * page DateSplitField.
30163  * 
30164  */
30165
30166
30167 /**
30168  * @class Roo.bootstrap.DateSplitField
30169  * @extends Roo.bootstrap.Component
30170  * Bootstrap DateSplitField class
30171  * @cfg {string} fieldLabel - the label associated
30172  * @cfg {Number} labelWidth set the width of label (0-12)
30173  * @cfg {String} labelAlign (top|left)
30174  * @cfg {Boolean} dayAllowBlank (true|false) default false
30175  * @cfg {Boolean} monthAllowBlank (true|false) default false
30176  * @cfg {Boolean} yearAllowBlank (true|false) default false
30177  * @cfg {string} dayPlaceholder 
30178  * @cfg {string} monthPlaceholder
30179  * @cfg {string} yearPlaceholder
30180  * @cfg {string} dayFormat default 'd'
30181  * @cfg {string} monthFormat default 'm'
30182  * @cfg {string} yearFormat default 'Y'
30183  * @cfg {Number} labellg set the width of label (1-12)
30184  * @cfg {Number} labelmd set the width of label (1-12)
30185  * @cfg {Number} labelsm set the width of label (1-12)
30186  * @cfg {Number} labelxs set the width of label (1-12)
30187
30188  *     
30189  * @constructor
30190  * Create a new DateSplitField
30191  * @param {Object} config The config object
30192  */
30193
30194 Roo.bootstrap.DateSplitField = function(config){
30195     Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30196     
30197     this.addEvents({
30198         // raw events
30199          /**
30200          * @event years
30201          * getting the data of years
30202          * @param {Roo.bootstrap.DateSplitField} this
30203          * @param {Object} years
30204          */
30205         "years" : true,
30206         /**
30207          * @event days
30208          * getting the data of days
30209          * @param {Roo.bootstrap.DateSplitField} this
30210          * @param {Object} days
30211          */
30212         "days" : true,
30213         /**
30214          * @event invalid
30215          * Fires after the field has been marked as invalid.
30216          * @param {Roo.form.Field} this
30217          * @param {String} msg The validation message
30218          */
30219         invalid : true,
30220        /**
30221          * @event valid
30222          * Fires after the field has been validated with no errors.
30223          * @param {Roo.form.Field} this
30224          */
30225         valid : true
30226     });
30227 };
30228
30229 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component,  {
30230     
30231     fieldLabel : '',
30232     labelAlign : 'top',
30233     labelWidth : 3,
30234     dayAllowBlank : false,
30235     monthAllowBlank : false,
30236     yearAllowBlank : false,
30237     dayPlaceholder : '',
30238     monthPlaceholder : '',
30239     yearPlaceholder : '',
30240     dayFormat : 'd',
30241     monthFormat : 'm',
30242     yearFormat : 'Y',
30243     isFormField : true,
30244     labellg : 0,
30245     labelmd : 0,
30246     labelsm : 0,
30247     labelxs : 0,
30248     
30249     getAutoCreate : function()
30250     {
30251         var cfg = {
30252             tag : 'div',
30253             cls : 'row roo-date-split-field-group',
30254             cn : [
30255                 {
30256                     tag : 'input',
30257                     type : 'hidden',
30258                     cls : 'form-hidden-field roo-date-split-field-group-value',
30259                     name : this.name
30260                 }
30261             ]
30262         };
30263         
30264         var labelCls = 'col-md-12';
30265         var contentCls = 'col-md-4';
30266         
30267         if(this.fieldLabel){
30268             
30269             var label = {
30270                 tag : 'div',
30271                 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30272                 cn : [
30273                     {
30274                         tag : 'label',
30275                         html : this.fieldLabel
30276                     }
30277                 ]
30278             };
30279             
30280             if(this.labelAlign == 'left'){
30281             
30282                 if(this.labelWidth > 12){
30283                     label.style = "width: " + this.labelWidth + 'px';
30284                 }
30285
30286                 if(this.labelWidth < 13 && this.labelmd == 0){
30287                     this.labelmd = this.labelWidth;
30288                 }
30289
30290                 if(this.labellg > 0){
30291                     labelCls = ' col-lg-' + this.labellg;
30292                     contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30293                 }
30294
30295                 if(this.labelmd > 0){
30296                     labelCls = ' col-md-' + this.labelmd;
30297                     contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30298                 }
30299
30300                 if(this.labelsm > 0){
30301                     labelCls = ' col-sm-' + this.labelsm;
30302                     contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30303                 }
30304
30305                 if(this.labelxs > 0){
30306                     labelCls = ' col-xs-' + this.labelxs;
30307                     contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30308                 }
30309             }
30310             
30311             label.cls += ' ' + labelCls;
30312             
30313             cfg.cn.push(label);
30314         }
30315         
30316         Roo.each(['day', 'month', 'year'], function(t){
30317             cfg.cn.push({
30318                 tag : 'div',
30319                 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30320             });
30321         }, this);
30322         
30323         return cfg;
30324     },
30325     
30326     inputEl: function ()
30327     {
30328         return this.el.select('.roo-date-split-field-group-value', true).first();
30329     },
30330     
30331     onRender : function(ct, position) 
30332     {
30333         var _this = this;
30334         
30335         Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30336         
30337         this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30338         
30339         this.dayField = new Roo.bootstrap.ComboBox({
30340             allowBlank : this.dayAllowBlank,
30341             alwaysQuery : true,
30342             displayField : 'value',
30343             editable : false,
30344             fieldLabel : '',
30345             forceSelection : true,
30346             mode : 'local',
30347             placeholder : this.dayPlaceholder,
30348             selectOnFocus : true,
30349             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30350             triggerAction : 'all',
30351             typeAhead : true,
30352             valueField : 'value',
30353             store : new Roo.data.SimpleStore({
30354                 data : (function() {    
30355                     var days = [];
30356                     _this.fireEvent('days', _this, days);
30357                     return days;
30358                 })(),
30359                 fields : [ 'value' ]
30360             }),
30361             listeners : {
30362                 select : function (_self, record, index)
30363                 {
30364                     _this.setValue(_this.getValue());
30365                 }
30366             }
30367         });
30368
30369         this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30370         
30371         this.monthField = new Roo.bootstrap.MonthField({
30372             after : '<i class=\"fa fa-calendar\"></i>',
30373             allowBlank : this.monthAllowBlank,
30374             placeholder : this.monthPlaceholder,
30375             readOnly : true,
30376             listeners : {
30377                 render : function (_self)
30378                 {
30379                     this.el.select('span.input-group-addon', true).first().on('click', function(e){
30380                         e.preventDefault();
30381                         _self.focus();
30382                     });
30383                 },
30384                 select : function (_self, oldvalue, newvalue)
30385                 {
30386                     _this.setValue(_this.getValue());
30387                 }
30388             }
30389         });
30390         
30391         this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30392         
30393         this.yearField = new Roo.bootstrap.ComboBox({
30394             allowBlank : this.yearAllowBlank,
30395             alwaysQuery : true,
30396             displayField : 'value',
30397             editable : false,
30398             fieldLabel : '',
30399             forceSelection : true,
30400             mode : 'local',
30401             placeholder : this.yearPlaceholder,
30402             selectOnFocus : true,
30403             tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30404             triggerAction : 'all',
30405             typeAhead : true,
30406             valueField : 'value',
30407             store : new Roo.data.SimpleStore({
30408                 data : (function() {
30409                     var years = [];
30410                     _this.fireEvent('years', _this, years);
30411                     return years;
30412                 })(),
30413                 fields : [ 'value' ]
30414             }),
30415             listeners : {
30416                 select : function (_self, record, index)
30417                 {
30418                     _this.setValue(_this.getValue());
30419                 }
30420             }
30421         });
30422
30423         this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30424     },
30425     
30426     setValue : function(v, format)
30427     {
30428         this.inputEl.dom.value = v;
30429         
30430         var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30431         
30432         var d = Date.parseDate(v, f);
30433         
30434         if(!d){
30435             this.validate();
30436             return;
30437         }
30438         
30439         this.setDay(d.format(this.dayFormat));
30440         this.setMonth(d.format(this.monthFormat));
30441         this.setYear(d.format(this.yearFormat));
30442         
30443         this.validate();
30444         
30445         return;
30446     },
30447     
30448     setDay : function(v)
30449     {
30450         this.dayField.setValue(v);
30451         this.inputEl.dom.value = this.getValue();
30452         this.validate();
30453         return;
30454     },
30455     
30456     setMonth : function(v)
30457     {
30458         this.monthField.setValue(v, true);
30459         this.inputEl.dom.value = this.getValue();
30460         this.validate();
30461         return;
30462     },
30463     
30464     setYear : function(v)
30465     {
30466         this.yearField.setValue(v);
30467         this.inputEl.dom.value = this.getValue();
30468         this.validate();
30469         return;
30470     },
30471     
30472     getDay : function()
30473     {
30474         return this.dayField.getValue();
30475     },
30476     
30477     getMonth : function()
30478     {
30479         return this.monthField.getValue();
30480     },
30481     
30482     getYear : function()
30483     {
30484         return this.yearField.getValue();
30485     },
30486     
30487     getValue : function()
30488     {
30489         var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30490         
30491         var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30492         
30493         return date;
30494     },
30495     
30496     reset : function()
30497     {
30498         this.setDay('');
30499         this.setMonth('');
30500         this.setYear('');
30501         this.inputEl.dom.value = '';
30502         this.validate();
30503         return;
30504     },
30505     
30506     validate : function()
30507     {
30508         var d = this.dayField.validate();
30509         var m = this.monthField.validate();
30510         var y = this.yearField.validate();
30511         
30512         var valid = true;
30513         
30514         if(
30515                 (!this.dayAllowBlank && !d) ||
30516                 (!this.monthAllowBlank && !m) ||
30517                 (!this.yearAllowBlank && !y)
30518         ){
30519             valid = false;
30520         }
30521         
30522         if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30523             return valid;
30524         }
30525         
30526         if(valid){
30527             this.markValid();
30528             return valid;
30529         }
30530         
30531         this.markInvalid();
30532         
30533         return valid;
30534     },
30535     
30536     markValid : function()
30537     {
30538         
30539         var label = this.el.select('label', true).first();
30540         var icon = this.el.select('i.fa-star', true).first();
30541
30542         if(label && icon){
30543             icon.remove();
30544         }
30545         
30546         this.fireEvent('valid', this);
30547     },
30548     
30549      /**
30550      * Mark this field as invalid
30551      * @param {String} msg The validation message
30552      */
30553     markInvalid : function(msg)
30554     {
30555         
30556         var label = this.el.select('label', true).first();
30557         var icon = this.el.select('i.fa-star', true).first();
30558
30559         if(label && !icon){
30560             this.el.select('.roo-date-split-field-label', true).createChild({
30561                 tag : 'i',
30562                 cls : 'text-danger fa fa-lg fa-star',
30563                 tooltip : 'This field is required',
30564                 style : 'margin-right:5px;'
30565             }, label, true);
30566         }
30567         
30568         this.fireEvent('invalid', this, msg);
30569     },
30570     
30571     clearInvalid : function()
30572     {
30573         var label = this.el.select('label', true).first();
30574         var icon = this.el.select('i.fa-star', true).first();
30575
30576         if(label && icon){
30577             icon.remove();
30578         }
30579         
30580         this.fireEvent('valid', this);
30581     },
30582     
30583     getName: function()
30584     {
30585         return this.name;
30586     }
30587     
30588 });
30589
30590  /**
30591  *
30592  * This is based on 
30593  * http://masonry.desandro.com
30594  *
30595  * The idea is to render all the bricks based on vertical width...
30596  *
30597  * The original code extends 'outlayer' - we might need to use that....
30598  * 
30599  */
30600
30601
30602 /**
30603  * @class Roo.bootstrap.LayoutMasonry
30604  * @extends Roo.bootstrap.Component
30605  * Bootstrap Layout Masonry class
30606  * 
30607  * @constructor
30608  * Create a new Element
30609  * @param {Object} config The config object
30610  */
30611
30612 Roo.bootstrap.LayoutMasonry = function(config){
30613     
30614     Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30615     
30616     this.bricks = [];
30617     
30618     Roo.bootstrap.LayoutMasonry.register(this);
30619     
30620     this.addEvents({
30621         // raw events
30622         /**
30623          * @event layout
30624          * Fire after layout the items
30625          * @param {Roo.bootstrap.LayoutMasonry} this
30626          * @param {Roo.EventObject} e
30627          */
30628         "layout" : true
30629     });
30630     
30631 };
30632
30633 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component,  {
30634     
30635     /**
30636      * @cfg {Boolean} isLayoutInstant = no animation?
30637      */   
30638     isLayoutInstant : false, // needed?
30639    
30640     /**
30641      * @cfg {Number} boxWidth  width of the columns
30642      */   
30643     boxWidth : 450,
30644     
30645       /**
30646      * @cfg {Number} boxHeight  - 0 for square, or fix it at a certian height
30647      */   
30648     boxHeight : 0,
30649     
30650     /**
30651      * @cfg {Number} padWidth padding below box..
30652      */   
30653     padWidth : 10, 
30654     
30655     /**
30656      * @cfg {Number} gutter gutter width..
30657      */   
30658     gutter : 10,
30659     
30660      /**
30661      * @cfg {Number} maxCols maximum number of columns
30662      */   
30663     
30664     maxCols: 0,
30665     
30666     /**
30667      * @cfg {Boolean} isAutoInitial defalut true
30668      */   
30669     isAutoInitial : true, 
30670     
30671     containerWidth: 0,
30672     
30673     /**
30674      * @cfg {Boolean} isHorizontal defalut false
30675      */   
30676     isHorizontal : false, 
30677
30678     currentSize : null,
30679     
30680     tag: 'div',
30681     
30682     cls: '',
30683     
30684     bricks: null, //CompositeElement
30685     
30686     cols : 1,
30687     
30688     _isLayoutInited : false,
30689     
30690 //    isAlternative : false, // only use for vertical layout...
30691     
30692     /**
30693      * @cfg {Number} alternativePadWidth padding below box..
30694      */   
30695     alternativePadWidth : 50,
30696     
30697     selectedBrick : [],
30698     
30699     getAutoCreate : function(){
30700         
30701         var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30702         
30703         var cfg = {
30704             tag: this.tag,
30705             cls: 'blog-masonary-wrapper ' + this.cls,
30706             cn : {
30707                 cls : 'mas-boxes masonary'
30708             }
30709         };
30710         
30711         return cfg;
30712     },
30713     
30714     getChildContainer: function( )
30715     {
30716         if (this.boxesEl) {
30717             return this.boxesEl;
30718         }
30719         
30720         this.boxesEl = this.el.select('.mas-boxes').first();
30721         
30722         return this.boxesEl;
30723     },
30724     
30725     
30726     initEvents : function()
30727     {
30728         var _this = this;
30729         
30730         if(this.isAutoInitial){
30731             Roo.log('hook children rendered');
30732             this.on('childrenrendered', function() {
30733                 Roo.log('children rendered');
30734                 _this.initial();
30735             } ,this);
30736         }
30737     },
30738     
30739     initial : function()
30740     {
30741         this.selectedBrick = [];
30742         
30743         this.currentSize = this.el.getBox(true);
30744         
30745         Roo.EventManager.onWindowResize(this.resize, this); 
30746
30747         if(!this.isAutoInitial){
30748             this.layout();
30749             return;
30750         }
30751         
30752         this.layout();
30753         
30754         return;
30755         //this.layout.defer(500,this);
30756         
30757     },
30758     
30759     resize : function()
30760     {
30761         var cs = this.el.getBox(true);
30762         
30763         if (
30764                 this.currentSize.width == cs.width && 
30765                 this.currentSize.x == cs.x && 
30766                 this.currentSize.height == cs.height && 
30767                 this.currentSize.y == cs.y 
30768         ) {
30769             Roo.log("no change in with or X or Y");
30770             return;
30771         }
30772         
30773         this.currentSize = cs;
30774         
30775         this.layout();
30776         
30777     },
30778     
30779     layout : function()
30780     {   
30781         this._resetLayout();
30782         
30783         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
30784         
30785         this.layoutItems( isInstant );
30786       
30787         this._isLayoutInited = true;
30788         
30789         this.fireEvent('layout', this);
30790         
30791     },
30792     
30793     _resetLayout : function()
30794     {
30795         if(this.isHorizontal){
30796             this.horizontalMeasureColumns();
30797             return;
30798         }
30799         
30800         this.verticalMeasureColumns();
30801         
30802     },
30803     
30804     verticalMeasureColumns : function()
30805     {
30806         this.getContainerWidth();
30807         
30808 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30809 //            this.colWidth = Math.floor(this.containerWidth * 0.8);
30810 //            return;
30811 //        }
30812         
30813         var boxWidth = this.boxWidth + this.padWidth;
30814         
30815         if(this.containerWidth < this.boxWidth){
30816             boxWidth = this.containerWidth
30817         }
30818         
30819         var containerWidth = this.containerWidth;
30820         
30821         var cols = Math.floor(containerWidth / boxWidth);
30822         
30823         this.cols = Math.max( cols, 1 );
30824         
30825         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
30826         
30827         var totalBoxWidth = this.cols * boxWidth - this.padWidth;
30828         
30829         var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
30830         
30831         this.colWidth = boxWidth + avail - this.padWidth;
30832         
30833         this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
30834         this.unitHeight = this.boxHeight > 0 ? this.boxHeight  : this.unitWidth;
30835     },
30836     
30837     horizontalMeasureColumns : function()
30838     {
30839         this.getContainerWidth();
30840         
30841         var boxWidth = this.boxWidth;
30842         
30843         if(this.containerWidth < boxWidth){
30844             boxWidth = this.containerWidth;
30845         }
30846         
30847         this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
30848         
30849         this.el.setHeight(boxWidth);
30850         
30851     },
30852     
30853     getContainerWidth : function()
30854     {
30855         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
30856     },
30857     
30858     layoutItems : function( isInstant )
30859     {
30860         Roo.log(this.bricks);
30861         
30862         var items = Roo.apply([], this.bricks);
30863         
30864         if(this.isHorizontal){
30865             this._horizontalLayoutItems( items , isInstant );
30866             return;
30867         }
30868         
30869 //        if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
30870 //            this._verticalAlternativeLayoutItems( items , isInstant );
30871 //            return;
30872 //        }
30873         
30874         this._verticalLayoutItems( items , isInstant );
30875         
30876     },
30877     
30878     _verticalLayoutItems : function ( items , isInstant)
30879     {
30880         if ( !items || !items.length ) {
30881             return;
30882         }
30883         
30884         var standard = [
30885             ['xs', 'xs', 'xs', 'tall'],
30886             ['xs', 'xs', 'tall'],
30887             ['xs', 'xs', 'sm'],
30888             ['xs', 'xs', 'xs'],
30889             ['xs', 'tall'],
30890             ['xs', 'sm'],
30891             ['xs', 'xs'],
30892             ['xs'],
30893             
30894             ['sm', 'xs', 'xs'],
30895             ['sm', 'xs'],
30896             ['sm'],
30897             
30898             ['tall', 'xs', 'xs', 'xs'],
30899             ['tall', 'xs', 'xs'],
30900             ['tall', 'xs'],
30901             ['tall']
30902             
30903         ];
30904         
30905         var queue = [];
30906         
30907         var boxes = [];
30908         
30909         var box = [];
30910         
30911         Roo.each(items, function(item, k){
30912             
30913             switch (item.size) {
30914                 // these layouts take up a full box,
30915                 case 'md' :
30916                 case 'md-left' :
30917                 case 'md-right' :
30918                 case 'wide' :
30919                     
30920                     if(box.length){
30921                         boxes.push(box);
30922                         box = [];
30923                     }
30924                     
30925                     boxes.push([item]);
30926                     
30927                     break;
30928                     
30929                 case 'xs' :
30930                 case 'sm' :
30931                 case 'tall' :
30932                     
30933                     box.push(item);
30934                     
30935                     break;
30936                 default :
30937                     break;
30938                     
30939             }
30940             
30941         }, this);
30942         
30943         if(box.length){
30944             boxes.push(box);
30945             box = [];
30946         }
30947         
30948         var filterPattern = function(box, length)
30949         {
30950             if(!box.length){
30951                 return;
30952             }
30953             
30954             var match = false;
30955             
30956             var pattern = box.slice(0, length);
30957             
30958             var format = [];
30959             
30960             Roo.each(pattern, function(i){
30961                 format.push(i.size);
30962             }, this);
30963             
30964             Roo.each(standard, function(s){
30965                 
30966                 if(String(s) != String(format)){
30967                     return;
30968                 }
30969                 
30970                 match = true;
30971                 return false;
30972                 
30973             }, this);
30974             
30975             if(!match && length == 1){
30976                 return;
30977             }
30978             
30979             if(!match){
30980                 filterPattern(box, length - 1);
30981                 return;
30982             }
30983                 
30984             queue.push(pattern);
30985
30986             box = box.slice(length, box.length);
30987
30988             filterPattern(box, 4);
30989
30990             return;
30991             
30992         }
30993         
30994         Roo.each(boxes, function(box, k){
30995             
30996             if(!box.length){
30997                 return;
30998             }
30999             
31000             if(box.length == 1){
31001                 queue.push(box);
31002                 return;
31003             }
31004             
31005             filterPattern(box, 4);
31006             
31007         }, this);
31008         
31009         this._processVerticalLayoutQueue( queue, isInstant );
31010         
31011     },
31012     
31013 //    _verticalAlternativeLayoutItems : function( items , isInstant )
31014 //    {
31015 //        if ( !items || !items.length ) {
31016 //            return;
31017 //        }
31018 //
31019 //        this._processVerticalAlternativeLayoutQueue( items, isInstant );
31020 //        
31021 //    },
31022     
31023     _horizontalLayoutItems : function ( items , isInstant)
31024     {
31025         if ( !items || !items.length || items.length < 3) {
31026             return;
31027         }
31028         
31029         items.reverse();
31030         
31031         var eItems = items.slice(0, 3);
31032         
31033         items = items.slice(3, items.length);
31034         
31035         var standard = [
31036             ['xs', 'xs', 'xs', 'wide'],
31037             ['xs', 'xs', 'wide'],
31038             ['xs', 'xs', 'sm'],
31039             ['xs', 'xs', 'xs'],
31040             ['xs', 'wide'],
31041             ['xs', 'sm'],
31042             ['xs', 'xs'],
31043             ['xs'],
31044             
31045             ['sm', 'xs', 'xs'],
31046             ['sm', 'xs'],
31047             ['sm'],
31048             
31049             ['wide', 'xs', 'xs', 'xs'],
31050             ['wide', 'xs', 'xs'],
31051             ['wide', 'xs'],
31052             ['wide'],
31053             
31054             ['wide-thin']
31055         ];
31056         
31057         var queue = [];
31058         
31059         var boxes = [];
31060         
31061         var box = [];
31062         
31063         Roo.each(items, function(item, k){
31064             
31065             switch (item.size) {
31066                 case 'md' :
31067                 case 'md-left' :
31068                 case 'md-right' :
31069                 case 'tall' :
31070                     
31071                     if(box.length){
31072                         boxes.push(box);
31073                         box = [];
31074                     }
31075                     
31076                     boxes.push([item]);
31077                     
31078                     break;
31079                     
31080                 case 'xs' :
31081                 case 'sm' :
31082                 case 'wide' :
31083                 case 'wide-thin' :
31084                     
31085                     box.push(item);
31086                     
31087                     break;
31088                 default :
31089                     break;
31090                     
31091             }
31092             
31093         }, this);
31094         
31095         if(box.length){
31096             boxes.push(box);
31097             box = [];
31098         }
31099         
31100         var filterPattern = function(box, length)
31101         {
31102             if(!box.length){
31103                 return;
31104             }
31105             
31106             var match = false;
31107             
31108             var pattern = box.slice(0, length);
31109             
31110             var format = [];
31111             
31112             Roo.each(pattern, function(i){
31113                 format.push(i.size);
31114             }, this);
31115             
31116             Roo.each(standard, function(s){
31117                 
31118                 if(String(s) != String(format)){
31119                     return;
31120                 }
31121                 
31122                 match = true;
31123                 return false;
31124                 
31125             }, this);
31126             
31127             if(!match && length == 1){
31128                 return;
31129             }
31130             
31131             if(!match){
31132                 filterPattern(box, length - 1);
31133                 return;
31134             }
31135                 
31136             queue.push(pattern);
31137
31138             box = box.slice(length, box.length);
31139
31140             filterPattern(box, 4);
31141
31142             return;
31143             
31144         }
31145         
31146         Roo.each(boxes, function(box, k){
31147             
31148             if(!box.length){
31149                 return;
31150             }
31151             
31152             if(box.length == 1){
31153                 queue.push(box);
31154                 return;
31155             }
31156             
31157             filterPattern(box, 4);
31158             
31159         }, this);
31160         
31161         
31162         var prune = [];
31163         
31164         var pos = this.el.getBox(true);
31165         
31166         var minX = pos.x;
31167         
31168         var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31169         
31170         var hit_end = false;
31171         
31172         Roo.each(queue, function(box){
31173             
31174             if(hit_end){
31175                 
31176                 Roo.each(box, function(b){
31177                 
31178                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31179                     b.el.hide();
31180
31181                 }, this);
31182
31183                 return;
31184             }
31185             
31186             var mx = 0;
31187             
31188             Roo.each(box, function(b){
31189                 
31190                 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31191                 b.el.show();
31192
31193                 mx = Math.max(mx, b.x);
31194                 
31195             }, this);
31196             
31197             maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31198             
31199             if(maxX < minX){
31200                 
31201                 Roo.each(box, function(b){
31202                 
31203                     b.el.setVisibilityMode(Roo.Element.DISPLAY);
31204                     b.el.hide();
31205                     
31206                 }, this);
31207                 
31208                 hit_end = true;
31209                 
31210                 return;
31211             }
31212             
31213             prune.push(box);
31214             
31215         }, this);
31216         
31217         this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31218     },
31219     
31220     /** Sets position of item in DOM
31221     * @param {Element} item
31222     * @param {Number} x - horizontal position
31223     * @param {Number} y - vertical position
31224     * @param {Boolean} isInstant - disables transitions
31225     */
31226     _processVerticalLayoutQueue : function( queue, isInstant )
31227     {
31228         var pos = this.el.getBox(true);
31229         var x = pos.x;
31230         var y = pos.y;
31231         var maxY = [];
31232         
31233         for (var i = 0; i < this.cols; i++){
31234             maxY[i] = pos.y;
31235         }
31236         
31237         Roo.each(queue, function(box, k){
31238             
31239             var col = k % this.cols;
31240             
31241             Roo.each(box, function(b,kk){
31242                 
31243                 b.el.position('absolute');
31244                 
31245                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31246                 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31247                 
31248                 if(b.size == 'md-left' || b.size == 'md-right'){
31249                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31250                     height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31251                 }
31252                 
31253                 b.el.setWidth(width);
31254                 b.el.setHeight(height);
31255                 // iframe?
31256                 b.el.select('iframe',true).setSize(width,height);
31257                 
31258             }, this);
31259             
31260             for (var i = 0; i < this.cols; i++){
31261                 
31262                 if(maxY[i] < maxY[col]){
31263                     col = i;
31264                     continue;
31265                 }
31266                 
31267                 col = Math.min(col, i);
31268                 
31269             }
31270             
31271             x = pos.x + col * (this.colWidth + this.padWidth);
31272             
31273             y = maxY[col];
31274             
31275             var positions = [];
31276             
31277             switch (box.length){
31278                 case 1 :
31279                     positions = this.getVerticalOneBoxColPositions(x, y, box);
31280                     break;
31281                 case 2 :
31282                     positions = this.getVerticalTwoBoxColPositions(x, y, box);
31283                     break;
31284                 case 3 :
31285                     positions = this.getVerticalThreeBoxColPositions(x, y, box);
31286                     break;
31287                 case 4 :
31288                     positions = this.getVerticalFourBoxColPositions(x, y, box);
31289                     break;
31290                 default :
31291                     break;
31292             }
31293             
31294             Roo.each(box, function(b,kk){
31295                 
31296                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31297                 
31298                 var sz = b.el.getSize();
31299                 
31300                 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31301                 
31302             }, this);
31303             
31304         }, this);
31305         
31306         var mY = 0;
31307         
31308         for (var i = 0; i < this.cols; i++){
31309             mY = Math.max(mY, maxY[i]);
31310         }
31311         
31312         this.el.setHeight(mY - pos.y);
31313         
31314     },
31315     
31316 //    _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31317 //    {
31318 //        var pos = this.el.getBox(true);
31319 //        var x = pos.x;
31320 //        var y = pos.y;
31321 //        var maxX = pos.right;
31322 //        
31323 //        var maxHeight = 0;
31324 //        
31325 //        Roo.each(items, function(item, k){
31326 //            
31327 //            var c = k % 2;
31328 //            
31329 //            item.el.position('absolute');
31330 //                
31331 //            var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31332 //
31333 //            item.el.setWidth(width);
31334 //
31335 //            var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31336 //
31337 //            item.el.setHeight(height);
31338 //            
31339 //            if(c == 0){
31340 //                item.el.setXY([x, y], isInstant ? false : true);
31341 //            } else {
31342 //                item.el.setXY([maxX - width, y], isInstant ? false : true);
31343 //            }
31344 //            
31345 //            y = y + height + this.alternativePadWidth;
31346 //            
31347 //            maxHeight = maxHeight + height + this.alternativePadWidth;
31348 //            
31349 //        }, this);
31350 //        
31351 //        this.el.setHeight(maxHeight);
31352 //        
31353 //    },
31354     
31355     _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31356     {
31357         var pos = this.el.getBox(true);
31358         
31359         var minX = pos.x;
31360         var minY = pos.y;
31361         
31362         var maxX = pos.right;
31363         
31364         this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31365         
31366         var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31367         
31368         Roo.each(queue, function(box, k){
31369             
31370             Roo.each(box, function(b, kk){
31371                 
31372                 b.el.position('absolute');
31373                 
31374                 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31375                 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31376                 
31377                 if(b.size == 'md-left' || b.size == 'md-right'){
31378                     width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31379                     height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31380                 }
31381                 
31382                 b.el.setWidth(width);
31383                 b.el.setHeight(height);
31384                 
31385             }, this);
31386             
31387             if(!box.length){
31388                 return;
31389             }
31390             
31391             var positions = [];
31392             
31393             switch (box.length){
31394                 case 1 :
31395                     positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31396                     break;
31397                 case 2 :
31398                     positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31399                     break;
31400                 case 3 :
31401                     positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31402                     break;
31403                 case 4 :
31404                     positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31405                     break;
31406                 default :
31407                     break;
31408             }
31409             
31410             Roo.each(box, function(b,kk){
31411                 
31412                 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31413                 
31414                 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31415                 
31416             }, this);
31417             
31418         }, this);
31419         
31420     },
31421     
31422     _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31423     {
31424         Roo.each(eItems, function(b,k){
31425             
31426             b.size = (k == 0) ? 'sm' : 'xs';
31427             b.x = (k == 0) ? 2 : 1;
31428             b.y = (k == 0) ? 2 : 1;
31429             
31430             b.el.position('absolute');
31431             
31432             var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31433                 
31434             b.el.setWidth(width);
31435             
31436             var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31437             
31438             b.el.setHeight(height);
31439             
31440         }, this);
31441
31442         var positions = [];
31443         
31444         positions.push({
31445             x : maxX - this.unitWidth * 2 - this.gutter,
31446             y : minY
31447         });
31448         
31449         positions.push({
31450             x : maxX - this.unitWidth,
31451             y : minY + (this.unitWidth + this.gutter) * 2
31452         });
31453         
31454         positions.push({
31455             x : maxX - this.unitWidth * 3 - this.gutter * 2,
31456             y : minY
31457         });
31458         
31459         Roo.each(eItems, function(b,k){
31460             
31461             b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31462
31463         }, this);
31464         
31465     },
31466     
31467     getVerticalOneBoxColPositions : function(x, y, box)
31468     {
31469         var pos = [];
31470         
31471         var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31472         
31473         if(box[0].size == 'md-left'){
31474             rand = 0;
31475         }
31476         
31477         if(box[0].size == 'md-right'){
31478             rand = 1;
31479         }
31480         
31481         pos.push({
31482             x : x + (this.unitWidth + this.gutter) * rand,
31483             y : y
31484         });
31485         
31486         return pos;
31487     },
31488     
31489     getVerticalTwoBoxColPositions : function(x, y, box)
31490     {
31491         var pos = [];
31492         
31493         if(box[0].size == 'xs'){
31494             
31495             pos.push({
31496                 x : x,
31497                 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31498             });
31499
31500             pos.push({
31501                 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31502                 y : y
31503             });
31504             
31505             return pos;
31506             
31507         }
31508         
31509         pos.push({
31510             x : x,
31511             y : y
31512         });
31513
31514         pos.push({
31515             x : x + (this.unitWidth + this.gutter) * 2,
31516             y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31517         });
31518         
31519         return pos;
31520         
31521     },
31522     
31523     getVerticalThreeBoxColPositions : function(x, y, box)
31524     {
31525         var pos = [];
31526         
31527         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31528             
31529             pos.push({
31530                 x : x,
31531                 y : y
31532             });
31533
31534             pos.push({
31535                 x : x + (this.unitWidth + this.gutter) * 1,
31536                 y : y
31537             });
31538             
31539             pos.push({
31540                 x : x + (this.unitWidth + this.gutter) * 2,
31541                 y : y
31542             });
31543             
31544             return pos;
31545             
31546         }
31547         
31548         if(box[0].size == 'xs' && box[1].size == 'xs'){
31549             
31550             pos.push({
31551                 x : x,
31552                 y : y
31553             });
31554
31555             pos.push({
31556                 x : x,
31557                 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31558             });
31559             
31560             pos.push({
31561                 x : x + (this.unitWidth + this.gutter) * 1,
31562                 y : y
31563             });
31564             
31565             return pos;
31566             
31567         }
31568         
31569         pos.push({
31570             x : x,
31571             y : y
31572         });
31573
31574         pos.push({
31575             x : x + (this.unitWidth + this.gutter) * 2,
31576             y : y
31577         });
31578
31579         pos.push({
31580             x : x + (this.unitWidth + this.gutter) * 2,
31581             y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31582         });
31583             
31584         return pos;
31585         
31586     },
31587     
31588     getVerticalFourBoxColPositions : function(x, y, box)
31589     {
31590         var pos = [];
31591         
31592         if(box[0].size == 'xs'){
31593             
31594             pos.push({
31595                 x : x,
31596                 y : y
31597             });
31598
31599             pos.push({
31600                 x : x,
31601                 y : y + (this.unitHeight + this.gutter) * 1
31602             });
31603             
31604             pos.push({
31605                 x : x,
31606                 y : y + (this.unitHeight + this.gutter) * 2
31607             });
31608             
31609             pos.push({
31610                 x : x + (this.unitWidth + this.gutter) * 1,
31611                 y : y
31612             });
31613             
31614             return pos;
31615             
31616         }
31617         
31618         pos.push({
31619             x : x,
31620             y : y
31621         });
31622
31623         pos.push({
31624             x : x + (this.unitWidth + this.gutter) * 2,
31625             y : y
31626         });
31627
31628         pos.push({
31629             x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31630             y : y + (this.unitHeight + this.gutter) * 1
31631         });
31632
31633         pos.push({
31634             x : x + (this.unitWidth + this.gutter) * 2,
31635             y : y + (this.unitWidth + this.gutter) * 2
31636         });
31637
31638         return pos;
31639         
31640     },
31641     
31642     getHorizontalOneBoxColPositions : function(maxX, minY, box)
31643     {
31644         var pos = [];
31645         
31646         if(box[0].size == 'md-left'){
31647             pos.push({
31648                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31649                 y : minY
31650             });
31651             
31652             return pos;
31653         }
31654         
31655         if(box[0].size == 'md-right'){
31656             pos.push({
31657                 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31658                 y : minY + (this.unitWidth + this.gutter) * 1
31659             });
31660             
31661             return pos;
31662         }
31663         
31664         var rand = Math.floor(Math.random() * (4 - box[0].y));
31665         
31666         pos.push({
31667             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31668             y : minY + (this.unitWidth + this.gutter) * rand
31669         });
31670         
31671         return pos;
31672         
31673     },
31674     
31675     getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31676     {
31677         var pos = [];
31678         
31679         if(box[0].size == 'xs'){
31680             
31681             pos.push({
31682                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31683                 y : minY
31684             });
31685
31686             pos.push({
31687                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31688                 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31689             });
31690             
31691             return pos;
31692             
31693         }
31694         
31695         pos.push({
31696             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31697             y : minY
31698         });
31699
31700         pos.push({
31701             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31702             y : minY + (this.unitWidth + this.gutter) * 2
31703         });
31704         
31705         return pos;
31706         
31707     },
31708     
31709     getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31710     {
31711         var pos = [];
31712         
31713         if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31714             
31715             pos.push({
31716                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31717                 y : minY
31718             });
31719
31720             pos.push({
31721                 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31722                 y : minY + (this.unitWidth + this.gutter) * 1
31723             });
31724             
31725             pos.push({
31726                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31727                 y : minY + (this.unitWidth + this.gutter) * 2
31728             });
31729             
31730             return pos;
31731             
31732         }
31733         
31734         if(box[0].size == 'xs' && box[1].size == 'xs'){
31735             
31736             pos.push({
31737                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31738                 y : minY
31739             });
31740
31741             pos.push({
31742                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31743                 y : minY
31744             });
31745             
31746             pos.push({
31747                 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31748                 y : minY + (this.unitWidth + this.gutter) * 1
31749             });
31750             
31751             return pos;
31752             
31753         }
31754         
31755         pos.push({
31756             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31757             y : minY
31758         });
31759
31760         pos.push({
31761             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31762             y : minY + (this.unitWidth + this.gutter) * 2
31763         });
31764
31765         pos.push({
31766             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31767             y : minY + (this.unitWidth + this.gutter) * 2
31768         });
31769             
31770         return pos;
31771         
31772     },
31773     
31774     getHorizontalFourBoxColPositions : function(maxX, minY, box)
31775     {
31776         var pos = [];
31777         
31778         if(box[0].size == 'xs'){
31779             
31780             pos.push({
31781                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31782                 y : minY
31783             });
31784
31785             pos.push({
31786                 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31787                 y : minY
31788             });
31789             
31790             pos.push({
31791                 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),
31792                 y : minY
31793             });
31794             
31795             pos.push({
31796                 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
31797                 y : minY + (this.unitWidth + this.gutter) * 1
31798             });
31799             
31800             return pos;
31801             
31802         }
31803         
31804         pos.push({
31805             x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31806             y : minY
31807         });
31808         
31809         pos.push({
31810             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31811             y : minY + (this.unitWidth + this.gutter) * 2
31812         });
31813         
31814         pos.push({
31815             x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
31816             y : minY + (this.unitWidth + this.gutter) * 2
31817         });
31818         
31819         pos.push({
31820             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),
31821             y : minY + (this.unitWidth + this.gutter) * 2
31822         });
31823
31824         return pos;
31825         
31826     },
31827     
31828     /**
31829     * remove a Masonry Brick
31830     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
31831     */
31832     removeBrick : function(brick_id)
31833     {
31834         if (!brick_id) {
31835             return;
31836         }
31837         
31838         for (var i = 0; i<this.bricks.length; i++) {
31839             if (this.bricks[i].id == brick_id) {
31840                 this.bricks.splice(i,1);
31841                 this.el.dom.removeChild(Roo.get(brick_id).dom);
31842                 this.initial();
31843             }
31844         }
31845     },
31846     
31847     /**
31848     * adds a Masonry Brick
31849     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31850     */
31851     addBrick : function(cfg)
31852     {
31853         var cn = new Roo.bootstrap.MasonryBrick(cfg);
31854         //this.register(cn);
31855         cn.parentId = this.id;
31856         cn.onRender(this.el, null);
31857         return cn;
31858     },
31859     
31860     /**
31861     * register a Masonry Brick
31862     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
31863     */
31864     
31865     register : function(brick)
31866     {
31867         this.bricks.push(brick);
31868         brick.masonryId = this.id;
31869     },
31870     
31871     /**
31872     * clear all the Masonry Brick
31873     */
31874     clearAll : function()
31875     {
31876         this.bricks = [];
31877         //this.getChildContainer().dom.innerHTML = "";
31878         this.el.dom.innerHTML = '';
31879     },
31880     
31881     getSelected : function()
31882     {
31883         if (!this.selectedBrick) {
31884             return false;
31885         }
31886         
31887         return this.selectedBrick;
31888     }
31889 });
31890
31891 Roo.apply(Roo.bootstrap.LayoutMasonry, {
31892     
31893     groups: {},
31894      /**
31895     * register a Masonry Layout
31896     * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
31897     */
31898     
31899     register : function(layout)
31900     {
31901         this.groups[layout.id] = layout;
31902     },
31903     /**
31904     * fetch a  Masonry Layout based on the masonry layout ID
31905     * @param {string} the masonry layout to add
31906     * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
31907     */
31908     
31909     get: function(layout_id) {
31910         if (typeof(this.groups[layout_id]) == 'undefined') {
31911             return false;
31912         }
31913         return this.groups[layout_id] ;
31914     }
31915     
31916     
31917     
31918 });
31919
31920  
31921
31922  /**
31923  *
31924  * This is based on 
31925  * http://masonry.desandro.com
31926  *
31927  * The idea is to render all the bricks based on vertical width...
31928  *
31929  * The original code extends 'outlayer' - we might need to use that....
31930  * 
31931  */
31932
31933
31934 /**
31935  * @class Roo.bootstrap.LayoutMasonryAuto
31936  * @extends Roo.bootstrap.Component
31937  * Bootstrap Layout Masonry class
31938  * 
31939  * @constructor
31940  * Create a new Element
31941  * @param {Object} config The config object
31942  */
31943
31944 Roo.bootstrap.LayoutMasonryAuto = function(config){
31945     Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
31946 };
31947
31948 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component,  {
31949     
31950       /**
31951      * @cfg {Boolean} isFitWidth  - resize the width..
31952      */   
31953     isFitWidth : false,  // options..
31954     /**
31955      * @cfg {Boolean} isOriginLeft = left align?
31956      */   
31957     isOriginLeft : true,
31958     /**
31959      * @cfg {Boolean} isOriginTop = top align?
31960      */   
31961     isOriginTop : false,
31962     /**
31963      * @cfg {Boolean} isLayoutInstant = no animation?
31964      */   
31965     isLayoutInstant : false, // needed?
31966     /**
31967      * @cfg {Boolean} isResizingContainer = not sure if this is used..
31968      */   
31969     isResizingContainer : true,
31970     /**
31971      * @cfg {Number} columnWidth  width of the columns 
31972      */   
31973     
31974     columnWidth : 0,
31975     
31976     /**
31977      * @cfg {Number} maxCols maximum number of columns
31978      */   
31979     
31980     maxCols: 0,
31981     /**
31982      * @cfg {Number} padHeight padding below box..
31983      */   
31984     
31985     padHeight : 10, 
31986     
31987     /**
31988      * @cfg {Boolean} isAutoInitial defalut true
31989      */   
31990     
31991     isAutoInitial : true, 
31992     
31993     // private?
31994     gutter : 0,
31995     
31996     containerWidth: 0,
31997     initialColumnWidth : 0,
31998     currentSize : null,
31999     
32000     colYs : null, // array.
32001     maxY : 0,
32002     padWidth: 10,
32003     
32004     
32005     tag: 'div',
32006     cls: '',
32007     bricks: null, //CompositeElement
32008     cols : 0, // array?
32009     // element : null, // wrapped now this.el
32010     _isLayoutInited : null, 
32011     
32012     
32013     getAutoCreate : function(){
32014         
32015         var cfg = {
32016             tag: this.tag,
32017             cls: 'blog-masonary-wrapper ' + this.cls,
32018             cn : {
32019                 cls : 'mas-boxes masonary'
32020             }
32021         };
32022         
32023         return cfg;
32024     },
32025     
32026     getChildContainer: function( )
32027     {
32028         if (this.boxesEl) {
32029             return this.boxesEl;
32030         }
32031         
32032         this.boxesEl = this.el.select('.mas-boxes').first();
32033         
32034         return this.boxesEl;
32035     },
32036     
32037     
32038     initEvents : function()
32039     {
32040         var _this = this;
32041         
32042         if(this.isAutoInitial){
32043             Roo.log('hook children rendered');
32044             this.on('childrenrendered', function() {
32045                 Roo.log('children rendered');
32046                 _this.initial();
32047             } ,this);
32048         }
32049         
32050     },
32051     
32052     initial : function()
32053     {
32054         this.reloadItems();
32055
32056         this.currentSize = this.el.getBox(true);
32057
32058         /// was window resize... - let's see if this works..
32059         Roo.EventManager.onWindowResize(this.resize, this); 
32060
32061         if(!this.isAutoInitial){
32062             this.layout();
32063             return;
32064         }
32065         
32066         this.layout.defer(500,this);
32067     },
32068     
32069     reloadItems: function()
32070     {
32071         this.bricks = this.el.select('.masonry-brick', true);
32072         
32073         this.bricks.each(function(b) {
32074             //Roo.log(b.getSize());
32075             if (!b.attr('originalwidth')) {
32076                 b.attr('originalwidth',  b.getSize().width);
32077             }
32078             
32079         });
32080         
32081         Roo.log(this.bricks.elements.length);
32082     },
32083     
32084     resize : function()
32085     {
32086         Roo.log('resize');
32087         var cs = this.el.getBox(true);
32088         
32089         if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32090             Roo.log("no change in with or X");
32091             return;
32092         }
32093         this.currentSize = cs;
32094         this.layout();
32095     },
32096     
32097     layout : function()
32098     {
32099          Roo.log('layout');
32100         this._resetLayout();
32101         //this._manageStamps();
32102       
32103         // don't animate first layout
32104         var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32105         this.layoutItems( isInstant );
32106       
32107         // flag for initalized
32108         this._isLayoutInited = true;
32109     },
32110     
32111     layoutItems : function( isInstant )
32112     {
32113         //var items = this._getItemsForLayout( this.items );
32114         // original code supports filtering layout items.. we just ignore it..
32115         
32116         this._layoutItems( this.bricks , isInstant );
32117       
32118         this._postLayout();
32119     },
32120     _layoutItems : function ( items , isInstant)
32121     {
32122        //this.fireEvent( 'layout', this, items );
32123     
32124
32125         if ( !items || !items.elements.length ) {
32126           // no items, emit event with empty array
32127             return;
32128         }
32129
32130         var queue = [];
32131         items.each(function(item) {
32132             Roo.log("layout item");
32133             Roo.log(item);
32134             // get x/y object from method
32135             var position = this._getItemLayoutPosition( item );
32136             // enqueue
32137             position.item = item;
32138             position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32139             queue.push( position );
32140         }, this);
32141       
32142         this._processLayoutQueue( queue );
32143     },
32144     /** Sets position of item in DOM
32145     * @param {Element} item
32146     * @param {Number} x - horizontal position
32147     * @param {Number} y - vertical position
32148     * @param {Boolean} isInstant - disables transitions
32149     */
32150     _processLayoutQueue : function( queue )
32151     {
32152         for ( var i=0, len = queue.length; i < len; i++ ) {
32153             var obj = queue[i];
32154             obj.item.position('absolute');
32155             obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32156         }
32157     },
32158       
32159     
32160     /**
32161     * Any logic you want to do after each layout,
32162     * i.e. size the container
32163     */
32164     _postLayout : function()
32165     {
32166         this.resizeContainer();
32167     },
32168     
32169     resizeContainer : function()
32170     {
32171         if ( !this.isResizingContainer ) {
32172             return;
32173         }
32174         var size = this._getContainerSize();
32175         if ( size ) {
32176             this.el.setSize(size.width,size.height);
32177             this.boxesEl.setSize(size.width,size.height);
32178         }
32179     },
32180     
32181     
32182     
32183     _resetLayout : function()
32184     {
32185         //this.getSize();  // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32186         this.colWidth = this.el.getWidth();
32187         //this.gutter = this.el.getWidth(); 
32188         
32189         this.measureColumns();
32190
32191         // reset column Y
32192         var i = this.cols;
32193         this.colYs = [];
32194         while (i--) {
32195             this.colYs.push( 0 );
32196         }
32197     
32198         this.maxY = 0;
32199     },
32200
32201     measureColumns : function()
32202     {
32203         this.getContainerWidth();
32204       // if columnWidth is 0, default to outerWidth of first item
32205         if ( !this.columnWidth ) {
32206             var firstItem = this.bricks.first();
32207             Roo.log(firstItem);
32208             this.columnWidth  = this.containerWidth;
32209             if (firstItem && firstItem.attr('originalwidth') ) {
32210                 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32211             }
32212             // columnWidth fall back to item of first element
32213             Roo.log("set column width?");
32214                         this.initialColumnWidth = this.columnWidth  ;
32215
32216             // if first elem has no width, default to size of container
32217             
32218         }
32219         
32220         
32221         if (this.initialColumnWidth) {
32222             this.columnWidth = this.initialColumnWidth;
32223         }
32224         
32225         
32226             
32227         // column width is fixed at the top - however if container width get's smaller we should
32228         // reduce it...
32229         
32230         // this bit calcs how man columns..
32231             
32232         var columnWidth = this.columnWidth += this.gutter;
32233       
32234         // calculate columns
32235         var containerWidth = this.containerWidth + this.gutter;
32236         
32237         var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32238         // fix rounding errors, typically with gutters
32239         var excess = columnWidth - containerWidth % columnWidth;
32240         
32241         
32242         // if overshoot is less than a pixel, round up, otherwise floor it
32243         var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32244         cols = Math[ mathMethod ]( cols );
32245         this.cols = Math.max( cols, 1 );
32246         this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32247         
32248          // padding positioning..
32249         var totalColWidth = this.cols * this.columnWidth;
32250         var padavail = this.containerWidth - totalColWidth;
32251         // so for 2 columns - we need 3 'pads'
32252         
32253         var padNeeded = (1+this.cols) * this.padWidth;
32254         
32255         var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32256         
32257         this.columnWidth += padExtra
32258         //this.padWidth = Math.floor(padavail /  ( this.cols));
32259         
32260         // adjust colum width so that padding is fixed??
32261         
32262         // we have 3 columns ... total = width * 3
32263         // we have X left over... that should be used by 
32264         
32265         //if (this.expandC) {
32266             
32267         //}
32268         
32269         
32270         
32271     },
32272     
32273     getContainerWidth : function()
32274     {
32275        /* // container is parent if fit width
32276         var container = this.isFitWidth ? this.element.parentNode : this.element;
32277         // check that this.size and size are there
32278         // IE8 triggers resize on body size change, so they might not be
32279         
32280         var size = getSize( container );  //FIXME
32281         this.containerWidth = size && size.innerWidth; //FIXME
32282         */
32283          
32284         this.containerWidth = this.el.getBox(true).width;  //maybe use getComputedWidth
32285         
32286     },
32287     
32288     _getItemLayoutPosition : function( item )  // what is item?
32289     {
32290         // we resize the item to our columnWidth..
32291       
32292         item.setWidth(this.columnWidth);
32293         item.autoBoxAdjust  = false;
32294         
32295         var sz = item.getSize();
32296  
32297         // how many columns does this brick span
32298         var remainder = this.containerWidth % this.columnWidth;
32299         
32300         var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32301         // round if off by 1 pixel, otherwise use ceil
32302         var colSpan = Math[ mathMethod ]( sz.width  / this.columnWidth );
32303         colSpan = Math.min( colSpan, this.cols );
32304         
32305         // normally this should be '1' as we dont' currently allow multi width columns..
32306         
32307         var colGroup = this._getColGroup( colSpan );
32308         // get the minimum Y value from the columns
32309         var minimumY = Math.min.apply( Math, colGroup );
32310         Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32311         
32312         var shortColIndex = colGroup.indexOf(  minimumY ); // broken on ie8..?? probably...
32313          
32314         // position the brick
32315         var position = {
32316             x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32317             y: this.currentSize.y + minimumY + this.padHeight
32318         };
32319         
32320         Roo.log(position);
32321         // apply setHeight to necessary columns
32322         var setHeight = minimumY + sz.height + this.padHeight;
32323         //Roo.log([ 'setHeight',  minimumY, sz.height, setHeight ]);
32324         
32325         var setSpan = this.cols + 1 - colGroup.length;
32326         for ( var i = 0; i < setSpan; i++ ) {
32327           this.colYs[ shortColIndex + i ] = setHeight ;
32328         }
32329       
32330         return position;
32331     },
32332     
32333     /**
32334      * @param {Number} colSpan - number of columns the element spans
32335      * @returns {Array} colGroup
32336      */
32337     _getColGroup : function( colSpan )
32338     {
32339         if ( colSpan < 2 ) {
32340           // if brick spans only one column, use all the column Ys
32341           return this.colYs;
32342         }
32343       
32344         var colGroup = [];
32345         // how many different places could this brick fit horizontally
32346         var groupCount = this.cols + 1 - colSpan;
32347         // for each group potential horizontal position
32348         for ( var i = 0; i < groupCount; i++ ) {
32349           // make an array of colY values for that one group
32350           var groupColYs = this.colYs.slice( i, i + colSpan );
32351           // and get the max value of the array
32352           colGroup[i] = Math.max.apply( Math, groupColYs );
32353         }
32354         return colGroup;
32355     },
32356     /*
32357     _manageStamp : function( stamp )
32358     {
32359         var stampSize =  stamp.getSize();
32360         var offset = stamp.getBox();
32361         // get the columns that this stamp affects
32362         var firstX = this.isOriginLeft ? offset.x : offset.right;
32363         var lastX = firstX + stampSize.width;
32364         var firstCol = Math.floor( firstX / this.columnWidth );
32365         firstCol = Math.max( 0, firstCol );
32366         
32367         var lastCol = Math.floor( lastX / this.columnWidth );
32368         // lastCol should not go over if multiple of columnWidth #425
32369         lastCol -= lastX % this.columnWidth ? 0 : 1;
32370         lastCol = Math.min( this.cols - 1, lastCol );
32371         
32372         // set colYs to bottom of the stamp
32373         var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32374             stampSize.height;
32375             
32376         for ( var i = firstCol; i <= lastCol; i++ ) {
32377           this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32378         }
32379     },
32380     */
32381     
32382     _getContainerSize : function()
32383     {
32384         this.maxY = Math.max.apply( Math, this.colYs );
32385         var size = {
32386             height: this.maxY
32387         };
32388       
32389         if ( this.isFitWidth ) {
32390             size.width = this._getContainerFitWidth();
32391         }
32392       
32393         return size;
32394     },
32395     
32396     _getContainerFitWidth : function()
32397     {
32398         var unusedCols = 0;
32399         // count unused columns
32400         var i = this.cols;
32401         while ( --i ) {
32402           if ( this.colYs[i] !== 0 ) {
32403             break;
32404           }
32405           unusedCols++;
32406         }
32407         // fit container to columns that have been used
32408         return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32409     },
32410     
32411     needsResizeLayout : function()
32412     {
32413         var previousWidth = this.containerWidth;
32414         this.getContainerWidth();
32415         return previousWidth !== this.containerWidth;
32416     }
32417  
32418 });
32419
32420  
32421
32422  /*
32423  * - LGPL
32424  *
32425  * element
32426  * 
32427  */
32428
32429 /**
32430  * @class Roo.bootstrap.MasonryBrick
32431  * @extends Roo.bootstrap.Component
32432  * Bootstrap MasonryBrick class
32433  * 
32434  * @constructor
32435  * Create a new MasonryBrick
32436  * @param {Object} config The config object
32437  */
32438
32439 Roo.bootstrap.MasonryBrick = function(config){
32440     
32441     Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32442     
32443     Roo.bootstrap.MasonryBrick.register(this);
32444     
32445     this.addEvents({
32446         // raw events
32447         /**
32448          * @event click
32449          * When a MasonryBrick is clcik
32450          * @param {Roo.bootstrap.MasonryBrick} this
32451          * @param {Roo.EventObject} e
32452          */
32453         "click" : true
32454     });
32455 };
32456
32457 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component,  {
32458     
32459     /**
32460      * @cfg {String} title
32461      */   
32462     title : '',
32463     /**
32464      * @cfg {String} html
32465      */   
32466     html : '',
32467     /**
32468      * @cfg {String} bgimage
32469      */   
32470     bgimage : '',
32471     /**
32472      * @cfg {String} videourl
32473      */   
32474     videourl : '',
32475     /**
32476      * @cfg {String} cls
32477      */   
32478     cls : '',
32479     /**
32480      * @cfg {String} href
32481      */   
32482     href : '',
32483     /**
32484      * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32485      */   
32486     size : 'xs',
32487     
32488     /**
32489      * @cfg {String} placetitle (center|bottom)
32490      */   
32491     placetitle : '',
32492     
32493     /**
32494      * @cfg {Boolean} isFitContainer defalut true
32495      */   
32496     isFitContainer : true, 
32497     
32498     /**
32499      * @cfg {Boolean} preventDefault defalut false
32500      */   
32501     preventDefault : false, 
32502     
32503     /**
32504      * @cfg {Boolean} inverse defalut false
32505      */   
32506     maskInverse : false, 
32507     
32508     getAutoCreate : function()
32509     {
32510         if(!this.isFitContainer){
32511             return this.getSplitAutoCreate();
32512         }
32513         
32514         var cls = 'masonry-brick masonry-brick-full';
32515         
32516         if(this.href.length){
32517             cls += ' masonry-brick-link';
32518         }
32519         
32520         if(this.bgimage.length){
32521             cls += ' masonry-brick-image';
32522         }
32523         
32524         if(this.maskInverse){
32525             cls += ' mask-inverse';
32526         }
32527         
32528         if(!this.html.length && !this.maskInverse && !this.videourl.length){
32529             cls += ' enable-mask';
32530         }
32531         
32532         if(this.size){
32533             cls += ' masonry-' + this.size + '-brick';
32534         }
32535         
32536         if(this.placetitle.length){
32537             
32538             switch (this.placetitle) {
32539                 case 'center' :
32540                     cls += ' masonry-center-title';
32541                     break;
32542                 case 'bottom' :
32543                     cls += ' masonry-bottom-title';
32544                     break;
32545                 default:
32546                     break;
32547             }
32548             
32549         } else {
32550             if(!this.html.length && !this.bgimage.length){
32551                 cls += ' masonry-center-title';
32552             }
32553
32554             if(!this.html.length && this.bgimage.length){
32555                 cls += ' masonry-bottom-title';
32556             }
32557         }
32558         
32559         if(this.cls){
32560             cls += ' ' + this.cls;
32561         }
32562         
32563         var cfg = {
32564             tag: (this.href.length) ? 'a' : 'div',
32565             cls: cls,
32566             cn: [
32567                 {
32568                     tag: 'div',
32569                     cls: 'masonry-brick-mask'
32570                 },
32571                 {
32572                     tag: 'div',
32573                     cls: 'masonry-brick-paragraph',
32574                     cn: []
32575                 }
32576             ]
32577         };
32578         
32579         if(this.href.length){
32580             cfg.href = this.href;
32581         }
32582         
32583         var cn = cfg.cn[1].cn;
32584         
32585         if(this.title.length){
32586             cn.push({
32587                 tag: 'h4',
32588                 cls: 'masonry-brick-title',
32589                 html: this.title
32590             });
32591         }
32592         
32593         if(this.html.length){
32594             cn.push({
32595                 tag: 'p',
32596                 cls: 'masonry-brick-text',
32597                 html: this.html
32598             });
32599         }
32600         
32601         if (!this.title.length && !this.html.length) {
32602             cfg.cn[1].cls += ' hide';
32603         }
32604         
32605         if(this.bgimage.length){
32606             cfg.cn.push({
32607                 tag: 'img',
32608                 cls: 'masonry-brick-image-view',
32609                 src: this.bgimage
32610             });
32611         }
32612         
32613         if(this.videourl.length){
32614             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32615             // youtube support only?
32616             cfg.cn.push({
32617                 tag: 'iframe',
32618                 cls: 'masonry-brick-image-view',
32619                 src: vurl,
32620                 frameborder : 0,
32621                 allowfullscreen : true
32622             });
32623         }
32624         
32625         return cfg;
32626         
32627     },
32628     
32629     getSplitAutoCreate : function()
32630     {
32631         var cls = 'masonry-brick masonry-brick-split';
32632         
32633         if(this.href.length){
32634             cls += ' masonry-brick-link';
32635         }
32636         
32637         if(this.bgimage.length){
32638             cls += ' masonry-brick-image';
32639         }
32640         
32641         if(this.size){
32642             cls += ' masonry-' + this.size + '-brick';
32643         }
32644         
32645         switch (this.placetitle) {
32646             case 'center' :
32647                 cls += ' masonry-center-title';
32648                 break;
32649             case 'bottom' :
32650                 cls += ' masonry-bottom-title';
32651                 break;
32652             default:
32653                 if(!this.bgimage.length){
32654                     cls += ' masonry-center-title';
32655                 }
32656
32657                 if(this.bgimage.length){
32658                     cls += ' masonry-bottom-title';
32659                 }
32660                 break;
32661         }
32662         
32663         if(this.cls){
32664             cls += ' ' + this.cls;
32665         }
32666         
32667         var cfg = {
32668             tag: (this.href.length) ? 'a' : 'div',
32669             cls: cls,
32670             cn: [
32671                 {
32672                     tag: 'div',
32673                     cls: 'masonry-brick-split-head',
32674                     cn: [
32675                         {
32676                             tag: 'div',
32677                             cls: 'masonry-brick-paragraph',
32678                             cn: []
32679                         }
32680                     ]
32681                 },
32682                 {
32683                     tag: 'div',
32684                     cls: 'masonry-brick-split-body',
32685                     cn: []
32686                 }
32687             ]
32688         };
32689         
32690         if(this.href.length){
32691             cfg.href = this.href;
32692         }
32693         
32694         if(this.title.length){
32695             cfg.cn[0].cn[0].cn.push({
32696                 tag: 'h4',
32697                 cls: 'masonry-brick-title',
32698                 html: this.title
32699             });
32700         }
32701         
32702         if(this.html.length){
32703             cfg.cn[1].cn.push({
32704                 tag: 'p',
32705                 cls: 'masonry-brick-text',
32706                 html: this.html
32707             });
32708         }
32709
32710         if(this.bgimage.length){
32711             cfg.cn[0].cn.push({
32712                 tag: 'img',
32713                 cls: 'masonry-brick-image-view',
32714                 src: this.bgimage
32715             });
32716         }
32717         
32718         if(this.videourl.length){
32719             var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32720             // youtube support only?
32721             cfg.cn[0].cn.cn.push({
32722                 tag: 'iframe',
32723                 cls: 'masonry-brick-image-view',
32724                 src: vurl,
32725                 frameborder : 0,
32726                 allowfullscreen : true
32727             });
32728         }
32729         
32730         return cfg;
32731     },
32732     
32733     initEvents: function() 
32734     {
32735         switch (this.size) {
32736             case 'xs' :
32737                 this.x = 1;
32738                 this.y = 1;
32739                 break;
32740             case 'sm' :
32741                 this.x = 2;
32742                 this.y = 2;
32743                 break;
32744             case 'md' :
32745             case 'md-left' :
32746             case 'md-right' :
32747                 this.x = 3;
32748                 this.y = 3;
32749                 break;
32750             case 'tall' :
32751                 this.x = 2;
32752                 this.y = 3;
32753                 break;
32754             case 'wide' :
32755                 this.x = 3;
32756                 this.y = 2;
32757                 break;
32758             case 'wide-thin' :
32759                 this.x = 3;
32760                 this.y = 1;
32761                 break;
32762                         
32763             default :
32764                 break;
32765         }
32766         
32767         if(Roo.isTouch){
32768             this.el.on('touchstart', this.onTouchStart, this);
32769             this.el.on('touchmove', this.onTouchMove, this);
32770             this.el.on('touchend', this.onTouchEnd, this);
32771             this.el.on('contextmenu', this.onContextMenu, this);
32772         } else {
32773             this.el.on('mouseenter'  ,this.enter, this);
32774             this.el.on('mouseleave', this.leave, this);
32775             this.el.on('click', this.onClick, this);
32776         }
32777         
32778         if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
32779             this.parent().bricks.push(this);   
32780         }
32781         
32782     },
32783     
32784     onClick: function(e, el)
32785     {
32786         var time = this.endTimer - this.startTimer;
32787         // Roo.log(e.preventDefault());
32788         if(Roo.isTouch){
32789             if(time > 1000){
32790                 e.preventDefault();
32791                 return;
32792             }
32793         }
32794         
32795         if(!this.preventDefault){
32796             return;
32797         }
32798         
32799         e.preventDefault();
32800         
32801         if (this.activeClass != '') {
32802             this.selectBrick();
32803         }
32804         
32805         this.fireEvent('click', this, e);
32806     },
32807     
32808     enter: function(e, el)
32809     {
32810         e.preventDefault();
32811         
32812         if(!this.isFitContainer || this.maskInverse || this.videourl.length){
32813             return;
32814         }
32815         
32816         if(this.bgimage.length && this.html.length){
32817             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32818         }
32819     },
32820     
32821     leave: function(e, el)
32822     {
32823         e.preventDefault();
32824         
32825         if(!this.isFitContainer || this.maskInverse  || this.videourl.length){
32826             return;
32827         }
32828         
32829         if(this.bgimage.length && this.html.length){
32830             this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32831         }
32832     },
32833     
32834     onTouchStart: function(e, el)
32835     {
32836 //        e.preventDefault();
32837         
32838         this.touchmoved = false;
32839         
32840         if(!this.isFitContainer){
32841             return;
32842         }
32843         
32844         if(!this.bgimage.length || !this.html.length){
32845             return;
32846         }
32847         
32848         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
32849         
32850         this.timer = new Date().getTime();
32851         
32852     },
32853     
32854     onTouchMove: function(e, el)
32855     {
32856         this.touchmoved = true;
32857     },
32858     
32859     onContextMenu : function(e,el)
32860     {
32861         e.preventDefault();
32862         e.stopPropagation();
32863         return false;
32864     },
32865     
32866     onTouchEnd: function(e, el)
32867     {
32868 //        e.preventDefault();
32869         
32870         if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
32871         
32872             this.leave(e,el);
32873             
32874             return;
32875         }
32876         
32877         if(!this.bgimage.length || !this.html.length){
32878             
32879             if(this.href.length){
32880                 window.location.href = this.href;
32881             }
32882             
32883             return;
32884         }
32885         
32886         if(!this.isFitContainer){
32887             return;
32888         }
32889         
32890         this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
32891         
32892         window.location.href = this.href;
32893     },
32894     
32895     //selection on single brick only
32896     selectBrick : function() {
32897         
32898         if (!this.parentId) {
32899             return;
32900         }
32901         
32902         var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
32903         var index = m.selectedBrick.indexOf(this.id);
32904         
32905         if ( index > -1) {
32906             m.selectedBrick.splice(index,1);
32907             this.el.removeClass(this.activeClass);
32908             return;
32909         }
32910         
32911         for(var i = 0; i < m.selectedBrick.length; i++) {
32912             var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
32913             b.el.removeClass(b.activeClass);
32914         }
32915         
32916         m.selectedBrick = [];
32917         
32918         m.selectedBrick.push(this.id);
32919         this.el.addClass(this.activeClass);
32920         return;
32921     },
32922     
32923     isSelected : function(){
32924         return this.el.hasClass(this.activeClass);
32925         
32926     }
32927 });
32928
32929 Roo.apply(Roo.bootstrap.MasonryBrick, {
32930     
32931     //groups: {},
32932     groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
32933      /**
32934     * register a Masonry Brick
32935     * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32936     */
32937     
32938     register : function(brick)
32939     {
32940         //this.groups[brick.id] = brick;
32941         this.groups.add(brick.id, brick);
32942     },
32943     /**
32944     * fetch a  masonry brick based on the masonry brick ID
32945     * @param {string} the masonry brick to add
32946     * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
32947     */
32948     
32949     get: function(brick_id) 
32950     {
32951         // if (typeof(this.groups[brick_id]) == 'undefined') {
32952         //     return false;
32953         // }
32954         // return this.groups[brick_id] ;
32955         
32956         if(this.groups.key(brick_id)) {
32957             return this.groups.key(brick_id);
32958         }
32959         
32960         return false;
32961     }
32962     
32963     
32964     
32965 });
32966
32967  /*
32968  * - LGPL
32969  *
32970  * element
32971  * 
32972  */
32973
32974 /**
32975  * @class Roo.bootstrap.Brick
32976  * @extends Roo.bootstrap.Component
32977  * Bootstrap Brick class
32978  * 
32979  * @constructor
32980  * Create a new Brick
32981  * @param {Object} config The config object
32982  */
32983
32984 Roo.bootstrap.Brick = function(config){
32985     Roo.bootstrap.Brick.superclass.constructor.call(this, config);
32986     
32987     this.addEvents({
32988         // raw events
32989         /**
32990          * @event click
32991          * When a Brick is click
32992          * @param {Roo.bootstrap.Brick} this
32993          * @param {Roo.EventObject} e
32994          */
32995         "click" : true
32996     });
32997 };
32998
32999 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component,  {
33000     
33001     /**
33002      * @cfg {String} title
33003      */   
33004     title : '',
33005     /**
33006      * @cfg {String} html
33007      */   
33008     html : '',
33009     /**
33010      * @cfg {String} bgimage
33011      */   
33012     bgimage : '',
33013     /**
33014      * @cfg {String} cls
33015      */   
33016     cls : '',
33017     /**
33018      * @cfg {String} href
33019      */   
33020     href : '',
33021     /**
33022      * @cfg {String} video
33023      */   
33024     video : '',
33025     /**
33026      * @cfg {Boolean} square
33027      */   
33028     square : true,
33029     
33030     getAutoCreate : function()
33031     {
33032         var cls = 'roo-brick';
33033         
33034         if(this.href.length){
33035             cls += ' roo-brick-link';
33036         }
33037         
33038         if(this.bgimage.length){
33039             cls += ' roo-brick-image';
33040         }
33041         
33042         if(!this.html.length && !this.bgimage.length){
33043             cls += ' roo-brick-center-title';
33044         }
33045         
33046         if(!this.html.length && this.bgimage.length){
33047             cls += ' roo-brick-bottom-title';
33048         }
33049         
33050         if(this.cls){
33051             cls += ' ' + this.cls;
33052         }
33053         
33054         var cfg = {
33055             tag: (this.href.length) ? 'a' : 'div',
33056             cls: cls,
33057             cn: [
33058                 {
33059                     tag: 'div',
33060                     cls: 'roo-brick-paragraph',
33061                     cn: []
33062                 }
33063             ]
33064         };
33065         
33066         if(this.href.length){
33067             cfg.href = this.href;
33068         }
33069         
33070         var cn = cfg.cn[0].cn;
33071         
33072         if(this.title.length){
33073             cn.push({
33074                 tag: 'h4',
33075                 cls: 'roo-brick-title',
33076                 html: this.title
33077             });
33078         }
33079         
33080         if(this.html.length){
33081             cn.push({
33082                 tag: 'p',
33083                 cls: 'roo-brick-text',
33084                 html: this.html
33085             });
33086         } else {
33087             cn.cls += ' hide';
33088         }
33089         
33090         if(this.bgimage.length){
33091             cfg.cn.push({
33092                 tag: 'img',
33093                 cls: 'roo-brick-image-view',
33094                 src: this.bgimage
33095             });
33096         }
33097         
33098         return cfg;
33099     },
33100     
33101     initEvents: function() 
33102     {
33103         if(this.title.length || this.html.length){
33104             this.el.on('mouseenter'  ,this.enter, this);
33105             this.el.on('mouseleave', this.leave, this);
33106         }
33107         
33108         Roo.EventManager.onWindowResize(this.resize, this); 
33109         
33110         if(this.bgimage.length){
33111             this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33112             this.imageEl.on('load', this.onImageLoad, this);
33113             return;
33114         }
33115         
33116         this.resize();
33117     },
33118     
33119     onImageLoad : function()
33120     {
33121         this.resize();
33122     },
33123     
33124     resize : function()
33125     {
33126         var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33127         
33128         paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33129         
33130         if(this.bgimage.length){
33131             var image = this.el.select('.roo-brick-image-view', true).first();
33132             
33133             image.setWidth(paragraph.getWidth());
33134             
33135             if(this.square){
33136                 image.setHeight(paragraph.getWidth());
33137             }
33138             
33139             this.el.setHeight(image.getHeight());
33140             paragraph.setHeight(image.getHeight());
33141             
33142         }
33143         
33144     },
33145     
33146     enter: function(e, el)
33147     {
33148         e.preventDefault();
33149         
33150         if(this.bgimage.length){
33151             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33152             this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33153         }
33154     },
33155     
33156     leave: function(e, el)
33157     {
33158         e.preventDefault();
33159         
33160         if(this.bgimage.length){
33161             this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33162             this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33163         }
33164     }
33165     
33166 });
33167
33168  
33169
33170  /*
33171  * - LGPL
33172  *
33173  * Number field 
33174  */
33175
33176 /**
33177  * @class Roo.bootstrap.NumberField
33178  * @extends Roo.bootstrap.Input
33179  * Bootstrap NumberField class
33180  * 
33181  * 
33182  * 
33183  * 
33184  * @constructor
33185  * Create a new NumberField
33186  * @param {Object} config The config object
33187  */
33188
33189 Roo.bootstrap.NumberField = function(config){
33190     Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33191 };
33192
33193 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33194     
33195     /**
33196      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33197      */
33198     allowDecimals : true,
33199     /**
33200      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33201      */
33202     decimalSeparator : ".",
33203     /**
33204      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33205      */
33206     decimalPrecision : 2,
33207     /**
33208      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33209      */
33210     allowNegative : true,
33211     
33212     /**
33213      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33214      */
33215     allowZero: true,
33216     /**
33217      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33218      */
33219     minValue : Number.NEGATIVE_INFINITY,
33220     /**
33221      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33222      */
33223     maxValue : Number.MAX_VALUE,
33224     /**
33225      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33226      */
33227     minText : "The minimum value for this field is {0}",
33228     /**
33229      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33230      */
33231     maxText : "The maximum value for this field is {0}",
33232     /**
33233      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
33234      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33235      */
33236     nanText : "{0} is not a valid number",
33237     /**
33238      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33239      */
33240     thousandsDelimiter : false,
33241     /**
33242      * @cfg {String} valueAlign alignment of value
33243      */
33244     valueAlign : "left",
33245
33246     getAutoCreate : function()
33247     {
33248         var hiddenInput = {
33249             tag: 'input',
33250             type: 'hidden',
33251             id: Roo.id(),
33252             cls: 'hidden-number-input'
33253         };
33254         
33255         if (this.name) {
33256             hiddenInput.name = this.name;
33257         }
33258         
33259         this.name = '';
33260         
33261         var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33262         
33263         this.name = hiddenInput.name;
33264         
33265         if(cfg.cn.length > 0) {
33266             cfg.cn.push(hiddenInput);
33267         }
33268         
33269         return cfg;
33270     },
33271
33272     // private
33273     initEvents : function()
33274     {   
33275         Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33276         
33277         var allowed = "0123456789";
33278         
33279         if(this.allowDecimals){
33280             allowed += this.decimalSeparator;
33281         }
33282         
33283         if(this.allowNegative){
33284             allowed += "-";
33285         }
33286         
33287         if(this.thousandsDelimiter) {
33288             allowed += ",";
33289         }
33290         
33291         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33292         
33293         var keyPress = function(e){
33294             
33295             var k = e.getKey();
33296             
33297             var c = e.getCharCode();
33298             
33299             if(
33300                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33301                     allowed.indexOf(String.fromCharCode(c)) === -1
33302             ){
33303                 e.stopEvent();
33304                 return;
33305             }
33306             
33307             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33308                 return;
33309             }
33310             
33311             if(allowed.indexOf(String.fromCharCode(c)) === -1){
33312                 e.stopEvent();
33313             }
33314         };
33315         
33316         this.el.on("keypress", keyPress, this);
33317     },
33318     
33319     validateValue : function(value)
33320     {
33321         
33322         if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33323             return false;
33324         }
33325         
33326         var num = this.parseValue(value);
33327         
33328         if(isNaN(num)){
33329             this.markInvalid(String.format(this.nanText, value));
33330             return false;
33331         }
33332         
33333         if(num < this.minValue){
33334             this.markInvalid(String.format(this.minText, this.minValue));
33335             return false;
33336         }
33337         
33338         if(num > this.maxValue){
33339             this.markInvalid(String.format(this.maxText, this.maxValue));
33340             return false;
33341         }
33342         
33343         return true;
33344     },
33345
33346     getValue : function()
33347     {
33348         var v = this.hiddenEl().getValue();
33349         
33350         return this.fixPrecision(this.parseValue(v));
33351     },
33352
33353     parseValue : function(value)
33354     {
33355         if(this.thousandsDelimiter) {
33356             value += "";
33357             r = new RegExp(",", "g");
33358             value = value.replace(r, "");
33359         }
33360         
33361         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33362         return isNaN(value) ? '' : value;
33363     },
33364
33365     fixPrecision : function(value)
33366     {
33367         if(this.thousandsDelimiter) {
33368             value += "";
33369             r = new RegExp(",", "g");
33370             value = value.replace(r, "");
33371         }
33372         
33373         var nan = isNaN(value);
33374         
33375         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33376             return nan ? '' : value;
33377         }
33378         return parseFloat(value).toFixed(this.decimalPrecision);
33379     },
33380
33381     setValue : function(v)
33382     {
33383         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33384         
33385         this.value = v;
33386         
33387         if(this.rendered){
33388             
33389             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33390             
33391             this.inputEl().dom.value = (v == '') ? '' :
33392                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33393             
33394             if(!this.allowZero && v === '0') {
33395                 this.hiddenEl().dom.value = '';
33396                 this.inputEl().dom.value = '';
33397             }
33398             
33399             this.validate();
33400         }
33401     },
33402
33403     decimalPrecisionFcn : function(v)
33404     {
33405         return Math.floor(v);
33406     },
33407
33408     beforeBlur : function()
33409     {
33410         var v = this.parseValue(this.getRawValue());
33411         
33412         if(v || v === 0 || v === ''){
33413             this.setValue(v);
33414         }
33415     },
33416     
33417     hiddenEl : function()
33418     {
33419         return this.el.select('input.hidden-number-input',true).first();
33420     }
33421     
33422 });
33423
33424  
33425
33426 /*
33427 * Licence: LGPL
33428 */
33429
33430 /**
33431  * @class Roo.bootstrap.DocumentSlider
33432  * @extends Roo.bootstrap.Component
33433  * Bootstrap DocumentSlider class
33434  * 
33435  * @constructor
33436  * Create a new DocumentViewer
33437  * @param {Object} config The config object
33438  */
33439
33440 Roo.bootstrap.DocumentSlider = function(config){
33441     Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33442     
33443     this.files = [];
33444     
33445     this.addEvents({
33446         /**
33447          * @event initial
33448          * Fire after initEvent
33449          * @param {Roo.bootstrap.DocumentSlider} this
33450          */
33451         "initial" : true,
33452         /**
33453          * @event update
33454          * Fire after update
33455          * @param {Roo.bootstrap.DocumentSlider} this
33456          */
33457         "update" : true,
33458         /**
33459          * @event click
33460          * Fire after click
33461          * @param {Roo.bootstrap.DocumentSlider} this
33462          */
33463         "click" : true
33464     });
33465 };
33466
33467 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component,  {
33468     
33469     files : false,
33470     
33471     indicator : 0,
33472     
33473     getAutoCreate : function()
33474     {
33475         var cfg = {
33476             tag : 'div',
33477             cls : 'roo-document-slider',
33478             cn : [
33479                 {
33480                     tag : 'div',
33481                     cls : 'roo-document-slider-header',
33482                     cn : [
33483                         {
33484                             tag : 'div',
33485                             cls : 'roo-document-slider-header-title'
33486                         }
33487                     ]
33488                 },
33489                 {
33490                     tag : 'div',
33491                     cls : 'roo-document-slider-body',
33492                     cn : [
33493                         {
33494                             tag : 'div',
33495                             cls : 'roo-document-slider-prev',
33496                             cn : [
33497                                 {
33498                                     tag : 'i',
33499                                     cls : 'fa fa-chevron-left'
33500                                 }
33501                             ]
33502                         },
33503                         {
33504                             tag : 'div',
33505                             cls : 'roo-document-slider-thumb',
33506                             cn : [
33507                                 {
33508                                     tag : 'img',
33509                                     cls : 'roo-document-slider-image'
33510                                 }
33511                             ]
33512                         },
33513                         {
33514                             tag : 'div',
33515                             cls : 'roo-document-slider-next',
33516                             cn : [
33517                                 {
33518                                     tag : 'i',
33519                                     cls : 'fa fa-chevron-right'
33520                                 }
33521                             ]
33522                         }
33523                     ]
33524                 }
33525             ]
33526         };
33527         
33528         return cfg;
33529     },
33530     
33531     initEvents : function()
33532     {
33533         this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33534         this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33535         
33536         this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33537         this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33538         
33539         this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33540         this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33541         
33542         this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33543         this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33544         
33545         this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33546         this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33547         
33548         this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33549         this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33550         
33551         this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33552         this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33553         
33554         this.thumbEl.on('click', this.onClick, this);
33555         
33556         this.prevIndicator.on('click', this.prev, this);
33557         
33558         this.nextIndicator.on('click', this.next, this);
33559         
33560     },
33561     
33562     initial : function()
33563     {
33564         if(this.files.length){
33565             this.indicator = 1;
33566             this.update()
33567         }
33568         
33569         this.fireEvent('initial', this);
33570     },
33571     
33572     update : function()
33573     {
33574         this.imageEl.attr('src', this.files[this.indicator - 1]);
33575         
33576         this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33577         
33578         this.prevIndicator.show();
33579         
33580         if(this.indicator == 1){
33581             this.prevIndicator.hide();
33582         }
33583         
33584         this.nextIndicator.show();
33585         
33586         if(this.indicator == this.files.length){
33587             this.nextIndicator.hide();
33588         }
33589         
33590         this.thumbEl.scrollTo('top');
33591         
33592         this.fireEvent('update', this);
33593     },
33594     
33595     onClick : function(e)
33596     {
33597         e.preventDefault();
33598         
33599         this.fireEvent('click', this);
33600     },
33601     
33602     prev : function(e)
33603     {
33604         e.preventDefault();
33605         
33606         this.indicator = Math.max(1, this.indicator - 1);
33607         
33608         this.update();
33609     },
33610     
33611     next : function(e)
33612     {
33613         e.preventDefault();
33614         
33615         this.indicator = Math.min(this.files.length, this.indicator + 1);
33616         
33617         this.update();
33618     }
33619 });
33620 /*
33621  * - LGPL
33622  *
33623  * RadioSet
33624  *
33625  *
33626  */
33627
33628 /**
33629  * @class Roo.bootstrap.RadioSet
33630  * @extends Roo.bootstrap.Input
33631  * Bootstrap RadioSet class
33632  * @cfg {String} indicatorpos (left|right) default left
33633  * @cfg {Boolean} inline (true|false) inline the element (default true)
33634  * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33635  * @constructor
33636  * Create a new RadioSet
33637  * @param {Object} config The config object
33638  */
33639
33640 Roo.bootstrap.RadioSet = function(config){
33641     
33642     Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33643     
33644     this.radioes = [];
33645     
33646     Roo.bootstrap.RadioSet.register(this);
33647     
33648     this.addEvents({
33649         /**
33650         * @event check
33651         * Fires when the element is checked or unchecked.
33652         * @param {Roo.bootstrap.RadioSet} this This radio
33653         * @param {Roo.bootstrap.Radio} item The checked item
33654         */
33655        check : true,
33656        /**
33657         * @event click
33658         * Fires when the element is click.
33659         * @param {Roo.bootstrap.RadioSet} this This radio set
33660         * @param {Roo.bootstrap.Radio} item The checked item
33661         * @param {Roo.EventObject} e The event object
33662         */
33663        click : true
33664     });
33665     
33666 };
33667
33668 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input,  {
33669
33670     radioes : false,
33671     
33672     inline : true,
33673     
33674     weight : '',
33675     
33676     indicatorpos : 'left',
33677     
33678     getAutoCreate : function()
33679     {
33680         var label = {
33681             tag : 'label',
33682             cls : 'roo-radio-set-label',
33683             cn : [
33684                 {
33685                     tag : 'span',
33686                     html : this.fieldLabel
33687                 }
33688             ]
33689         };
33690         
33691         if(this.indicatorpos == 'left'){
33692             label.cn.unshift({
33693                 tag : 'i',
33694                 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33695                 tooltip : 'This field is required'
33696             });
33697         } else {
33698             label.cn.push({
33699                 tag : 'i',
33700                 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33701                 tooltip : 'This field is required'
33702             });
33703         }
33704         
33705         var items = {
33706             tag : 'div',
33707             cls : 'roo-radio-set-items'
33708         };
33709         
33710         var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33711         
33712         if (align === 'left' && this.fieldLabel.length) {
33713             
33714             items = {
33715                 cls : "roo-radio-set-right", 
33716                 cn: [
33717                     items
33718                 ]
33719             };
33720             
33721             if(this.labelWidth > 12){
33722                 label.style = "width: " + this.labelWidth + 'px';
33723             }
33724             
33725             if(this.labelWidth < 13 && this.labelmd == 0){
33726                 this.labelmd = this.labelWidth;
33727             }
33728             
33729             if(this.labellg > 0){
33730                 label.cls += ' col-lg-' + this.labellg;
33731                 items.cls += ' col-lg-' + (12 - this.labellg);
33732             }
33733             
33734             if(this.labelmd > 0){
33735                 label.cls += ' col-md-' + this.labelmd;
33736                 items.cls += ' col-md-' + (12 - this.labelmd);
33737             }
33738             
33739             if(this.labelsm > 0){
33740                 label.cls += ' col-sm-' + this.labelsm;
33741                 items.cls += ' col-sm-' + (12 - this.labelsm);
33742             }
33743             
33744             if(this.labelxs > 0){
33745                 label.cls += ' col-xs-' + this.labelxs;
33746                 items.cls += ' col-xs-' + (12 - this.labelxs);
33747             }
33748         }
33749         
33750         var cfg = {
33751             tag : 'div',
33752             cls : 'roo-radio-set',
33753             cn : [
33754                 {
33755                     tag : 'input',
33756                     cls : 'roo-radio-set-input',
33757                     type : 'hidden',
33758                     name : this.name,
33759                     value : this.value ? this.value :  ''
33760                 },
33761                 label,
33762                 items
33763             ]
33764         };
33765         
33766         if(this.weight.length){
33767             cfg.cls += ' roo-radio-' + this.weight;
33768         }
33769         
33770         if(this.inline) {
33771             cfg.cls += ' roo-radio-set-inline';
33772         }
33773         
33774         var settings=this;
33775         ['xs','sm','md','lg'].map(function(size){
33776             if (settings[size]) {
33777                 cfg.cls += ' col-' + size + '-' + settings[size];
33778             }
33779         });
33780         
33781         return cfg;
33782         
33783     },
33784
33785     initEvents : function()
33786     {
33787         this.labelEl = this.el.select('.roo-radio-set-label', true).first();
33788         this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
33789         
33790         if(!this.fieldLabel.length){
33791             this.labelEl.hide();
33792         }
33793         
33794         this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
33795         this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
33796         
33797         this.indicator = this.indicatorEl();
33798         
33799         if(this.indicator){
33800             this.indicator.addClass('invisible');
33801         }
33802         
33803         this.originalValue = this.getValue();
33804         
33805     },
33806     
33807     inputEl: function ()
33808     {
33809         return this.el.select('.roo-radio-set-input', true).first();
33810     },
33811     
33812     getChildContainer : function()
33813     {
33814         return this.itemsEl;
33815     },
33816     
33817     register : function(item)
33818     {
33819         this.radioes.push(item);
33820         
33821     },
33822     
33823     validate : function()
33824     {   
33825         if(this.getVisibilityEl().hasClass('hidden')){
33826             return true;
33827         }
33828         
33829         var valid = false;
33830         
33831         Roo.each(this.radioes, function(i){
33832             if(!i.checked){
33833                 return;
33834             }
33835             
33836             valid = true;
33837             return false;
33838         });
33839         
33840         if(this.allowBlank) {
33841             return true;
33842         }
33843         
33844         if(this.disabled || valid){
33845             this.markValid();
33846             return true;
33847         }
33848         
33849         this.markInvalid();
33850         return false;
33851         
33852     },
33853     
33854     markValid : function()
33855     {
33856         if(this.labelEl.isVisible(true)){
33857             this.indicatorEl().removeClass('visible');
33858             this.indicatorEl().addClass('invisible');
33859         }
33860         
33861         this.el.removeClass([this.invalidClass, this.validClass]);
33862         this.el.addClass(this.validClass);
33863         
33864         this.fireEvent('valid', this);
33865     },
33866     
33867     markInvalid : function(msg)
33868     {
33869         if(this.allowBlank || this.disabled){
33870             return;
33871         }
33872         
33873         if(this.labelEl.isVisible(true)){
33874             this.indicatorEl().removeClass('invisible');
33875             this.indicatorEl().addClass('visible');
33876         }
33877         
33878         this.el.removeClass([this.invalidClass, this.validClass]);
33879         this.el.addClass(this.invalidClass);
33880         
33881         this.fireEvent('invalid', this, msg);
33882         
33883     },
33884     
33885     setValue : function(v, suppressEvent)
33886     {   
33887         if(this.value === v){
33888             return;
33889         }
33890         
33891         this.value = v;
33892         
33893         if(this.rendered){
33894             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
33895         }
33896         
33897         Roo.each(this.radioes, function(i){
33898             i.checked = false;
33899             i.el.removeClass('checked');
33900         });
33901         
33902         Roo.each(this.radioes, function(i){
33903             
33904             if(i.value === v || i.value.toString() === v.toString()){
33905                 i.checked = true;
33906                 i.el.addClass('checked');
33907                 
33908                 if(suppressEvent !== true){
33909                     this.fireEvent('check', this, i);
33910                 }
33911                 
33912                 return false;
33913             }
33914             
33915         }, this);
33916         
33917         this.validate();
33918     },
33919     
33920     clearInvalid : function(){
33921         
33922         if(!this.el || this.preventMark){
33923             return;
33924         }
33925         
33926         this.el.removeClass([this.invalidClass]);
33927         
33928         this.fireEvent('valid', this);
33929     }
33930     
33931 });
33932
33933 Roo.apply(Roo.bootstrap.RadioSet, {
33934     
33935     groups: {},
33936     
33937     register : function(set)
33938     {
33939         this.groups[set.name] = set;
33940     },
33941     
33942     get: function(name) 
33943     {
33944         if (typeof(this.groups[name]) == 'undefined') {
33945             return false;
33946         }
33947         
33948         return this.groups[name] ;
33949     }
33950     
33951 });
33952 /*
33953  * Based on:
33954  * Ext JS Library 1.1.1
33955  * Copyright(c) 2006-2007, Ext JS, LLC.
33956  *
33957  * Originally Released Under LGPL - original licence link has changed is not relivant.
33958  *
33959  * Fork - LGPL
33960  * <script type="text/javascript">
33961  */
33962
33963
33964 /**
33965  * @class Roo.bootstrap.SplitBar
33966  * @extends Roo.util.Observable
33967  * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
33968  * <br><br>
33969  * Usage:
33970  * <pre><code>
33971 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
33972                    Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
33973 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
33974 split.minSize = 100;
33975 split.maxSize = 600;
33976 split.animate = true;
33977 split.on('moved', splitterMoved);
33978 </code></pre>
33979  * @constructor
33980  * Create a new SplitBar
33981  * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar. 
33982  * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged 
33983  * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
33984  * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or  
33985                         Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
33986                         position of the SplitBar).
33987  */
33988 Roo.bootstrap.SplitBar = function(cfg){
33989     
33990     /** @private */
33991     
33992     //{
33993     //  dragElement : elm
33994     //  resizingElement: el,
33995         // optional..
33996     //    orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
33997     //    placement : Roo.bootstrap.SplitBar.LEFT  ,
33998         // existingProxy ???
33999     //}
34000     
34001     this.el = Roo.get(cfg.dragElement, true);
34002     this.el.dom.unselectable = "on";
34003     /** @private */
34004     this.resizingEl = Roo.get(cfg.resizingElement, true);
34005
34006     /**
34007      * @private
34008      * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34009      * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34010      * @type Number
34011      */
34012     this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34013     
34014     /**
34015      * The minimum size of the resizing element. (Defaults to 0)
34016      * @type Number
34017      */
34018     this.minSize = 0;
34019     
34020     /**
34021      * The maximum size of the resizing element. (Defaults to 2000)
34022      * @type Number
34023      */
34024     this.maxSize = 2000;
34025     
34026     /**
34027      * Whether to animate the transition to the new size
34028      * @type Boolean
34029      */
34030     this.animate = false;
34031     
34032     /**
34033      * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34034      * @type Boolean
34035      */
34036     this.useShim = false;
34037     
34038     /** @private */
34039     this.shim = null;
34040     
34041     if(!cfg.existingProxy){
34042         /** @private */
34043         this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34044     }else{
34045         this.proxy = Roo.get(cfg.existingProxy).dom;
34046     }
34047     /** @private */
34048     this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34049     
34050     /** @private */
34051     this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34052     
34053     /** @private */
34054     this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34055     
34056     /** @private */
34057     this.dragSpecs = {};
34058     
34059     /**
34060      * @private The adapter to use to positon and resize elements
34061      */
34062     this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34063     this.adapter.init(this);
34064     
34065     if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34066         /** @private */
34067         this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34068         this.el.addClass("roo-splitbar-h");
34069     }else{
34070         /** @private */
34071         this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34072         this.el.addClass("roo-splitbar-v");
34073     }
34074     
34075     this.addEvents({
34076         /**
34077          * @event resize
34078          * Fires when the splitter is moved (alias for {@link #event-moved})
34079          * @param {Roo.bootstrap.SplitBar} this
34080          * @param {Number} newSize the new width or height
34081          */
34082         "resize" : true,
34083         /**
34084          * @event moved
34085          * Fires when the splitter is moved
34086          * @param {Roo.bootstrap.SplitBar} this
34087          * @param {Number} newSize the new width or height
34088          */
34089         "moved" : true,
34090         /**
34091          * @event beforeresize
34092          * Fires before the splitter is dragged
34093          * @param {Roo.bootstrap.SplitBar} this
34094          */
34095         "beforeresize" : true,
34096
34097         "beforeapply" : true
34098     });
34099
34100     Roo.util.Observable.call(this);
34101 };
34102
34103 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34104     onStartProxyDrag : function(x, y){
34105         this.fireEvent("beforeresize", this);
34106         if(!this.overlay){
34107             var o = Roo.DomHelper.insertFirst(document.body,  {cls: "roo-drag-overlay", html: "&#160;"}, true);
34108             o.unselectable();
34109             o.enableDisplayMode("block");
34110             // all splitbars share the same overlay
34111             Roo.bootstrap.SplitBar.prototype.overlay = o;
34112         }
34113         this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34114         this.overlay.show();
34115         Roo.get(this.proxy).setDisplayed("block");
34116         var size = this.adapter.getElementSize(this);
34117         this.activeMinSize = this.getMinimumSize();;
34118         this.activeMaxSize = this.getMaximumSize();;
34119         var c1 = size - this.activeMinSize;
34120         var c2 = Math.max(this.activeMaxSize - size, 0);
34121         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34122             this.dd.resetConstraints();
34123             this.dd.setXConstraint(
34124                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2, 
34125                 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34126             );
34127             this.dd.setYConstraint(0, 0);
34128         }else{
34129             this.dd.resetConstraints();
34130             this.dd.setXConstraint(0, 0);
34131             this.dd.setYConstraint(
34132                 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2, 
34133                 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34134             );
34135          }
34136         this.dragSpecs.startSize = size;
34137         this.dragSpecs.startPoint = [x, y];
34138         Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34139     },
34140     
34141     /** 
34142      * @private Called after the drag operation by the DDProxy
34143      */
34144     onEndProxyDrag : function(e){
34145         Roo.get(this.proxy).setDisplayed(false);
34146         var endPoint = Roo.lib.Event.getXY(e);
34147         if(this.overlay){
34148             this.overlay.hide();
34149         }
34150         var newSize;
34151         if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34152             newSize = this.dragSpecs.startSize + 
34153                 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34154                     endPoint[0] - this.dragSpecs.startPoint[0] :
34155                     this.dragSpecs.startPoint[0] - endPoint[0]
34156                 );
34157         }else{
34158             newSize = this.dragSpecs.startSize + 
34159                 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34160                     endPoint[1] - this.dragSpecs.startPoint[1] :
34161                     this.dragSpecs.startPoint[1] - endPoint[1]
34162                 );
34163         }
34164         newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34165         if(newSize != this.dragSpecs.startSize){
34166             if(this.fireEvent('beforeapply', this, newSize) !== false){
34167                 this.adapter.setElementSize(this, newSize);
34168                 this.fireEvent("moved", this, newSize);
34169                 this.fireEvent("resize", this, newSize);
34170             }
34171         }
34172     },
34173     
34174     /**
34175      * Get the adapter this SplitBar uses
34176      * @return The adapter object
34177      */
34178     getAdapter : function(){
34179         return this.adapter;
34180     },
34181     
34182     /**
34183      * Set the adapter this SplitBar uses
34184      * @param {Object} adapter A SplitBar adapter object
34185      */
34186     setAdapter : function(adapter){
34187         this.adapter = adapter;
34188         this.adapter.init(this);
34189     },
34190     
34191     /**
34192      * Gets the minimum size for the resizing element
34193      * @return {Number} The minimum size
34194      */
34195     getMinimumSize : function(){
34196         return this.minSize;
34197     },
34198     
34199     /**
34200      * Sets the minimum size for the resizing element
34201      * @param {Number} minSize The minimum size
34202      */
34203     setMinimumSize : function(minSize){
34204         this.minSize = minSize;
34205     },
34206     
34207     /**
34208      * Gets the maximum size for the resizing element
34209      * @return {Number} The maximum size
34210      */
34211     getMaximumSize : function(){
34212         return this.maxSize;
34213     },
34214     
34215     /**
34216      * Sets the maximum size for the resizing element
34217      * @param {Number} maxSize The maximum size
34218      */
34219     setMaximumSize : function(maxSize){
34220         this.maxSize = maxSize;
34221     },
34222     
34223     /**
34224      * Sets the initialize size for the resizing element
34225      * @param {Number} size The initial size
34226      */
34227     setCurrentSize : function(size){
34228         var oldAnimate = this.animate;
34229         this.animate = false;
34230         this.adapter.setElementSize(this, size);
34231         this.animate = oldAnimate;
34232     },
34233     
34234     /**
34235      * Destroy this splitbar. 
34236      * @param {Boolean} removeEl True to remove the element
34237      */
34238     destroy : function(removeEl){
34239         if(this.shim){
34240             this.shim.remove();
34241         }
34242         this.dd.unreg();
34243         this.proxy.parentNode.removeChild(this.proxy);
34244         if(removeEl){
34245             this.el.remove();
34246         }
34247     }
34248 });
34249
34250 /**
34251  * @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.
34252  */
34253 Roo.bootstrap.SplitBar.createProxy = function(dir){
34254     var proxy = new Roo.Element(document.createElement("div"));
34255     proxy.unselectable();
34256     var cls = 'roo-splitbar-proxy';
34257     proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34258     document.body.appendChild(proxy.dom);
34259     return proxy.dom;
34260 };
34261
34262 /** 
34263  * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34264  * Default Adapter. It assumes the splitter and resizing element are not positioned
34265  * elements and only gets/sets the width of the element. Generally used for table based layouts.
34266  */
34267 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34268 };
34269
34270 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34271     // do nothing for now
34272     init : function(s){
34273     
34274     },
34275     /**
34276      * Called before drag operations to get the current size of the resizing element. 
34277      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34278      */
34279      getElementSize : function(s){
34280         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34281             return s.resizingEl.getWidth();
34282         }else{
34283             return s.resizingEl.getHeight();
34284         }
34285     },
34286     
34287     /**
34288      * Called after drag operations to set the size of the resizing element.
34289      * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34290      * @param {Number} newSize The new size to set
34291      * @param {Function} onComplete A function to be invoked when resizing is complete
34292      */
34293     setElementSize : function(s, newSize, onComplete){
34294         if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34295             if(!s.animate){
34296                 s.resizingEl.setWidth(newSize);
34297                 if(onComplete){
34298                     onComplete(s, newSize);
34299                 }
34300             }else{
34301                 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34302             }
34303         }else{
34304             
34305             if(!s.animate){
34306                 s.resizingEl.setHeight(newSize);
34307                 if(onComplete){
34308                     onComplete(s, newSize);
34309                 }
34310             }else{
34311                 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34312             }
34313         }
34314     }
34315 };
34316
34317 /** 
34318  *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34319  * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34320  * Adapter that  moves the splitter element to align with the resized sizing element. 
34321  * Used with an absolute positioned SplitBar.
34322  * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34323  * document.body, make sure you assign an id to the body element.
34324  */
34325 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34326     this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34327     this.container = Roo.get(container);
34328 };
34329
34330 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34331     init : function(s){
34332         this.basic.init(s);
34333     },
34334     
34335     getElementSize : function(s){
34336         return this.basic.getElementSize(s);
34337     },
34338     
34339     setElementSize : function(s, newSize, onComplete){
34340         this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34341     },
34342     
34343     moveSplitter : function(s){
34344         var yes = Roo.bootstrap.SplitBar;
34345         switch(s.placement){
34346             case yes.LEFT:
34347                 s.el.setX(s.resizingEl.getRight());
34348                 break;
34349             case yes.RIGHT:
34350                 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34351                 break;
34352             case yes.TOP:
34353                 s.el.setY(s.resizingEl.getBottom());
34354                 break;
34355             case yes.BOTTOM:
34356                 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34357                 break;
34358         }
34359     }
34360 };
34361
34362 /**
34363  * Orientation constant - Create a vertical SplitBar
34364  * @static
34365  * @type Number
34366  */
34367 Roo.bootstrap.SplitBar.VERTICAL = 1;
34368
34369 /**
34370  * Orientation constant - Create a horizontal SplitBar
34371  * @static
34372  * @type Number
34373  */
34374 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34375
34376 /**
34377  * Placement constant - The resizing element is to the left of the splitter element
34378  * @static
34379  * @type Number
34380  */
34381 Roo.bootstrap.SplitBar.LEFT = 1;
34382
34383 /**
34384  * Placement constant - The resizing element is to the right of the splitter element
34385  * @static
34386  * @type Number
34387  */
34388 Roo.bootstrap.SplitBar.RIGHT = 2;
34389
34390 /**
34391  * Placement constant - The resizing element is positioned above the splitter element
34392  * @static
34393  * @type Number
34394  */
34395 Roo.bootstrap.SplitBar.TOP = 3;
34396
34397 /**
34398  * Placement constant - The resizing element is positioned under splitter element
34399  * @static
34400  * @type Number
34401  */
34402 Roo.bootstrap.SplitBar.BOTTOM = 4;
34403 Roo.namespace("Roo.bootstrap.layout");/*
34404  * Based on:
34405  * Ext JS Library 1.1.1
34406  * Copyright(c) 2006-2007, Ext JS, LLC.
34407  *
34408  * Originally Released Under LGPL - original licence link has changed is not relivant.
34409  *
34410  * Fork - LGPL
34411  * <script type="text/javascript">
34412  */
34413
34414 /**
34415  * @class Roo.bootstrap.layout.Manager
34416  * @extends Roo.bootstrap.Component
34417  * Base class for layout managers.
34418  */
34419 Roo.bootstrap.layout.Manager = function(config)
34420 {
34421     Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34422
34423
34424
34425
34426
34427     /** false to disable window resize monitoring @type Boolean */
34428     this.monitorWindowResize = true;
34429     this.regions = {};
34430     this.addEvents({
34431         /**
34432          * @event layout
34433          * Fires when a layout is performed.
34434          * @param {Roo.LayoutManager} this
34435          */
34436         "layout" : true,
34437         /**
34438          * @event regionresized
34439          * Fires when the user resizes a region.
34440          * @param {Roo.LayoutRegion} region The resized region
34441          * @param {Number} newSize The new size (width for east/west, height for north/south)
34442          */
34443         "regionresized" : true,
34444         /**
34445          * @event regioncollapsed
34446          * Fires when a region is collapsed.
34447          * @param {Roo.LayoutRegion} region The collapsed region
34448          */
34449         "regioncollapsed" : true,
34450         /**
34451          * @event regionexpanded
34452          * Fires when a region is expanded.
34453          * @param {Roo.LayoutRegion} region The expanded region
34454          */
34455         "regionexpanded" : true
34456     });
34457     this.updating = false;
34458
34459     if (config.el) {
34460         this.el = Roo.get(config.el);
34461         this.initEvents();
34462     }
34463
34464 };
34465
34466 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34467
34468
34469     regions : null,
34470
34471     monitorWindowResize : true,
34472
34473
34474     updating : false,
34475
34476
34477     onRender : function(ct, position)
34478     {
34479         if(!this.el){
34480             this.el = Roo.get(ct);
34481             this.initEvents();
34482         }
34483         //this.fireEvent('render',this);
34484     },
34485
34486
34487     initEvents: function()
34488     {
34489
34490
34491         // ie scrollbar fix
34492         if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34493             document.body.scroll = "no";
34494         }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34495             this.el.position('relative');
34496         }
34497         this.id = this.el.id;
34498         this.el.addClass("roo-layout-container");
34499         Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34500         if(this.el.dom != document.body ) {
34501             this.el.on('resize', this.layout,this);
34502             this.el.on('show', this.layout,this);
34503         }
34504
34505     },
34506
34507     /**
34508      * Returns true if this layout is currently being updated
34509      * @return {Boolean}
34510      */
34511     isUpdating : function(){
34512         return this.updating;
34513     },
34514
34515     /**
34516      * Suspend the LayoutManager from doing auto-layouts while
34517      * making multiple add or remove calls
34518      */
34519     beginUpdate : function(){
34520         this.updating = true;
34521     },
34522
34523     /**
34524      * Restore auto-layouts and optionally disable the manager from performing a layout
34525      * @param {Boolean} noLayout true to disable a layout update
34526      */
34527     endUpdate : function(noLayout){
34528         this.updating = false;
34529         if(!noLayout){
34530             this.layout();
34531         }
34532     },
34533
34534     layout: function(){
34535         // abstract...
34536     },
34537
34538     onRegionResized : function(region, newSize){
34539         this.fireEvent("regionresized", region, newSize);
34540         this.layout();
34541     },
34542
34543     onRegionCollapsed : function(region){
34544         this.fireEvent("regioncollapsed", region);
34545     },
34546
34547     onRegionExpanded : function(region){
34548         this.fireEvent("regionexpanded", region);
34549     },
34550
34551     /**
34552      * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34553      * performs box-model adjustments.
34554      * @return {Object} The size as an object {width: (the width), height: (the height)}
34555      */
34556     getViewSize : function()
34557     {
34558         var size;
34559         if(this.el.dom != document.body){
34560             size = this.el.getSize();
34561         }else{
34562             size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34563         }
34564         size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34565         size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34566         return size;
34567     },
34568
34569     /**
34570      * Returns the Element this layout is bound to.
34571      * @return {Roo.Element}
34572      */
34573     getEl : function(){
34574         return this.el;
34575     },
34576
34577     /**
34578      * Returns the specified region.
34579      * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34580      * @return {Roo.LayoutRegion}
34581      */
34582     getRegion : function(target){
34583         return this.regions[target.toLowerCase()];
34584     },
34585
34586     onWindowResize : function(){
34587         if(this.monitorWindowResize){
34588             this.layout();
34589         }
34590     }
34591 });
34592 /*
34593  * Based on:
34594  * Ext JS Library 1.1.1
34595  * Copyright(c) 2006-2007, Ext JS, LLC.
34596  *
34597  * Originally Released Under LGPL - original licence link has changed is not relivant.
34598  *
34599  * Fork - LGPL
34600  * <script type="text/javascript">
34601  */
34602 /**
34603  * @class Roo.bootstrap.layout.Border
34604  * @extends Roo.bootstrap.layout.Manager
34605  * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34606  * please see: examples/bootstrap/nested.html<br><br>
34607  
34608 <b>The container the layout is rendered into can be either the body element or any other element.
34609 If it is not the body element, the container needs to either be an absolute positioned element,
34610 or you will need to add "position:relative" to the css of the container.  You will also need to specify
34611 the container size if it is not the body element.</b>
34612
34613 * @constructor
34614 * Create a new Border
34615 * @param {Object} config Configuration options
34616  */
34617 Roo.bootstrap.layout.Border = function(config){
34618     config = config || {};
34619     Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34620     
34621     
34622     
34623     Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34624         if(config[region]){
34625             config[region].region = region;
34626             this.addRegion(config[region]);
34627         }
34628     },this);
34629     
34630 };
34631
34632 Roo.bootstrap.layout.Border.regions =  ["north","south","east","west","center"];
34633
34634 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34635     /**
34636      * Creates and adds a new region if it doesn't already exist.
34637      * @param {String} target The target region key (north, south, east, west or center).
34638      * @param {Object} config The regions config object
34639      * @return {BorderLayoutRegion} The new region
34640      */
34641     addRegion : function(config)
34642     {
34643         if(!this.regions[config.region]){
34644             var r = this.factory(config);
34645             this.bindRegion(r);
34646         }
34647         return this.regions[config.region];
34648     },
34649
34650     // private (kinda)
34651     bindRegion : function(r){
34652         this.regions[r.config.region] = r;
34653         
34654         r.on("visibilitychange",    this.layout, this);
34655         r.on("paneladded",          this.layout, this);
34656         r.on("panelremoved",        this.layout, this);
34657         r.on("invalidated",         this.layout, this);
34658         r.on("resized",             this.onRegionResized, this);
34659         r.on("collapsed",           this.onRegionCollapsed, this);
34660         r.on("expanded",            this.onRegionExpanded, this);
34661     },
34662
34663     /**
34664      * Performs a layout update.
34665      */
34666     layout : function()
34667     {
34668         if(this.updating) {
34669             return;
34670         }
34671         
34672         // render all the rebions if they have not been done alreayd?
34673         Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34674             if(this.regions[region] && !this.regions[region].bodyEl){
34675                 this.regions[region].onRender(this.el)
34676             }
34677         },this);
34678         
34679         var size = this.getViewSize();
34680         var w = size.width;
34681         var h = size.height;
34682         var centerW = w;
34683         var centerH = h;
34684         var centerY = 0;
34685         var centerX = 0;
34686         //var x = 0, y = 0;
34687
34688         var rs = this.regions;
34689         var north = rs["north"];
34690         var south = rs["south"]; 
34691         var west = rs["west"];
34692         var east = rs["east"];
34693         var center = rs["center"];
34694         //if(this.hideOnLayout){ // not supported anymore
34695             //c.el.setStyle("display", "none");
34696         //}
34697         if(north && north.isVisible()){
34698             var b = north.getBox();
34699             var m = north.getMargins();
34700             b.width = w - (m.left+m.right);
34701             b.x = m.left;
34702             b.y = m.top;
34703             centerY = b.height + b.y + m.bottom;
34704             centerH -= centerY;
34705             north.updateBox(this.safeBox(b));
34706         }
34707         if(south && south.isVisible()){
34708             var b = south.getBox();
34709             var m = south.getMargins();
34710             b.width = w - (m.left+m.right);
34711             b.x = m.left;
34712             var totalHeight = (b.height + m.top + m.bottom);
34713             b.y = h - totalHeight + m.top;
34714             centerH -= totalHeight;
34715             south.updateBox(this.safeBox(b));
34716         }
34717         if(west && west.isVisible()){
34718             var b = west.getBox();
34719             var m = west.getMargins();
34720             b.height = centerH - (m.top+m.bottom);
34721             b.x = m.left;
34722             b.y = centerY + m.top;
34723             var totalWidth = (b.width + m.left + m.right);
34724             centerX += totalWidth;
34725             centerW -= totalWidth;
34726             west.updateBox(this.safeBox(b));
34727         }
34728         if(east && east.isVisible()){
34729             var b = east.getBox();
34730             var m = east.getMargins();
34731             b.height = centerH - (m.top+m.bottom);
34732             var totalWidth = (b.width + m.left + m.right);
34733             b.x = w - totalWidth + m.left;
34734             b.y = centerY + m.top;
34735             centerW -= totalWidth;
34736             east.updateBox(this.safeBox(b));
34737         }
34738         if(center){
34739             var m = center.getMargins();
34740             var centerBox = {
34741                 x: centerX + m.left,
34742                 y: centerY + m.top,
34743                 width: centerW - (m.left+m.right),
34744                 height: centerH - (m.top+m.bottom)
34745             };
34746             //if(this.hideOnLayout){
34747                 //center.el.setStyle("display", "block");
34748             //}
34749             center.updateBox(this.safeBox(centerBox));
34750         }
34751         this.el.repaint();
34752         this.fireEvent("layout", this);
34753     },
34754
34755     // private
34756     safeBox : function(box){
34757         box.width = Math.max(0, box.width);
34758         box.height = Math.max(0, box.height);
34759         return box;
34760     },
34761
34762     /**
34763      * Adds a ContentPanel (or subclass) to this layout.
34764      * @param {String} target The target region key (north, south, east, west or center).
34765      * @param {Roo.ContentPanel} panel The panel to add
34766      * @return {Roo.ContentPanel} The added panel
34767      */
34768     add : function(target, panel){
34769          
34770         target = target.toLowerCase();
34771         return this.regions[target].add(panel);
34772     },
34773
34774     /**
34775      * Remove a ContentPanel (or subclass) to this layout.
34776      * @param {String} target The target region key (north, south, east, west or center).
34777      * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
34778      * @return {Roo.ContentPanel} The removed panel
34779      */
34780     remove : function(target, panel){
34781         target = target.toLowerCase();
34782         return this.regions[target].remove(panel);
34783     },
34784
34785     /**
34786      * Searches all regions for a panel with the specified id
34787      * @param {String} panelId
34788      * @return {Roo.ContentPanel} The panel or null if it wasn't found
34789      */
34790     findPanel : function(panelId){
34791         var rs = this.regions;
34792         for(var target in rs){
34793             if(typeof rs[target] != "function"){
34794                 var p = rs[target].getPanel(panelId);
34795                 if(p){
34796                     return p;
34797                 }
34798             }
34799         }
34800         return null;
34801     },
34802
34803     /**
34804      * Searches all regions for a panel with the specified id and activates (shows) it.
34805      * @param {String/ContentPanel} panelId The panels id or the panel itself
34806      * @return {Roo.ContentPanel} The shown panel or null
34807      */
34808     showPanel : function(panelId) {
34809       var rs = this.regions;
34810       for(var target in rs){
34811          var r = rs[target];
34812          if(typeof r != "function"){
34813             if(r.hasPanel(panelId)){
34814                return r.showPanel(panelId);
34815             }
34816          }
34817       }
34818       return null;
34819    },
34820
34821    /**
34822      * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
34823      * @param {Roo.state.Provider} provider (optional) An alternate state provider
34824      */
34825    /*
34826     restoreState : function(provider){
34827         if(!provider){
34828             provider = Roo.state.Manager;
34829         }
34830         var sm = new Roo.LayoutStateManager();
34831         sm.init(this, provider);
34832     },
34833 */
34834  
34835  
34836     /**
34837      * Adds a xtype elements to the layout.
34838      * <pre><code>
34839
34840 layout.addxtype({
34841        xtype : 'ContentPanel',
34842        region: 'west',
34843        items: [ .... ]
34844    }
34845 );
34846
34847 layout.addxtype({
34848         xtype : 'NestedLayoutPanel',
34849         region: 'west',
34850         layout: {
34851            center: { },
34852            west: { }   
34853         },
34854         items : [ ... list of content panels or nested layout panels.. ]
34855    }
34856 );
34857 </code></pre>
34858      * @param {Object} cfg Xtype definition of item to add.
34859      */
34860     addxtype : function(cfg)
34861     {
34862         // basically accepts a pannel...
34863         // can accept a layout region..!?!?
34864         //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
34865         
34866         
34867         // theory?  children can only be panels??
34868         
34869         //if (!cfg.xtype.match(/Panel$/)) {
34870         //    return false;
34871         //}
34872         var ret = false;
34873         
34874         if (typeof(cfg.region) == 'undefined') {
34875             Roo.log("Failed to add Panel, region was not set");
34876             Roo.log(cfg);
34877             return false;
34878         }
34879         var region = cfg.region;
34880         delete cfg.region;
34881         
34882           
34883         var xitems = [];
34884         if (cfg.items) {
34885             xitems = cfg.items;
34886             delete cfg.items;
34887         }
34888         var nb = false;
34889         
34890         switch(cfg.xtype) 
34891         {
34892             case 'Content':  // ContentPanel (el, cfg)
34893             case 'Scroll':  // ContentPanel (el, cfg)
34894             case 'View': 
34895                 cfg.autoCreate = true;
34896                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34897                 //} else {
34898                 //    var el = this.el.createChild();
34899                 //    ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
34900                 //}
34901                 
34902                 this.add(region, ret);
34903                 break;
34904             
34905             /*
34906             case 'TreePanel': // our new panel!
34907                 cfg.el = this.el.createChild();
34908                 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34909                 this.add(region, ret);
34910                 break;
34911             */
34912             
34913             case 'Nest': 
34914                 // create a new Layout (which is  a Border Layout...
34915                 
34916                 var clayout = cfg.layout;
34917                 clayout.el  = this.el.createChild();
34918                 clayout.items   = clayout.items  || [];
34919                 
34920                 delete cfg.layout;
34921                 
34922                 // replace this exitems with the clayout ones..
34923                 xitems = clayout.items;
34924                  
34925                 // force background off if it's in center...
34926                 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
34927                     cfg.background = false;
34928                 }
34929                 cfg.layout  = new Roo.bootstrap.layout.Border(clayout);
34930                 
34931                 
34932                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34933                 //console.log('adding nested layout panel '  + cfg.toSource());
34934                 this.add(region, ret);
34935                 nb = {}; /// find first...
34936                 break;
34937             
34938             case 'Grid':
34939                 
34940                 // needs grid and region
34941                 
34942                 //var el = this.getRegion(region).el.createChild();
34943                 /*
34944                  *var el = this.el.createChild();
34945                 // create the grid first...
34946                 cfg.grid.container = el;
34947                 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
34948                 */
34949                 
34950                 if (region == 'center' && this.active ) {
34951                     cfg.background = false;
34952                 }
34953                 
34954                 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
34955                 
34956                 this.add(region, ret);
34957                 /*
34958                 if (cfg.background) {
34959                     // render grid on panel activation (if panel background)
34960                     ret.on('activate', function(gp) {
34961                         if (!gp.grid.rendered) {
34962                     //        gp.grid.render(el);
34963                         }
34964                     });
34965                 } else {
34966                   //  cfg.grid.render(el);
34967                 }
34968                 */
34969                 break;
34970            
34971            
34972             case 'Border': // it can get called on it'self... - might need to check if this is fixed?
34973                 // it was the old xcomponent building that caused this before.
34974                 // espeically if border is the top element in the tree.
34975                 ret = this;
34976                 break; 
34977                 
34978                     
34979                 
34980                 
34981                 
34982             default:
34983                 /*
34984                 if (typeof(Roo[cfg.xtype]) != 'undefined') {
34985                     
34986                     ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
34987                     this.add(region, ret);
34988                 } else {
34989                 */
34990                     Roo.log(cfg);
34991                     throw "Can not add '" + cfg.xtype + "' to Border";
34992                     return null;
34993              
34994                                 
34995              
34996         }
34997         this.beginUpdate();
34998         // add children..
34999         var region = '';
35000         var abn = {};
35001         Roo.each(xitems, function(i)  {
35002             region = nb && i.region ? i.region : false;
35003             
35004             var add = ret.addxtype(i);
35005            
35006             if (region) {
35007                 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35008                 if (!i.background) {
35009                     abn[region] = nb[region] ;
35010                 }
35011             }
35012             
35013         });
35014         this.endUpdate();
35015
35016         // make the last non-background panel active..
35017         //if (nb) { Roo.log(abn); }
35018         if (nb) {
35019             
35020             for(var r in abn) {
35021                 region = this.getRegion(r);
35022                 if (region) {
35023                     // tried using nb[r], but it does not work..
35024                      
35025                     region.showPanel(abn[r]);
35026                    
35027                 }
35028             }
35029         }
35030         return ret;
35031         
35032     },
35033     
35034     
35035 // private
35036     factory : function(cfg)
35037     {
35038         
35039         var validRegions = Roo.bootstrap.layout.Border.regions;
35040
35041         var target = cfg.region;
35042         cfg.mgr = this;
35043         
35044         var r = Roo.bootstrap.layout;
35045         Roo.log(target);
35046         switch(target){
35047             case "north":
35048                 return new r.North(cfg);
35049             case "south":
35050                 return new r.South(cfg);
35051             case "east":
35052                 return new r.East(cfg);
35053             case "west":
35054                 return new r.West(cfg);
35055             case "center":
35056                 return new r.Center(cfg);
35057         }
35058         throw 'Layout region "'+target+'" not supported.';
35059     }
35060     
35061     
35062 });
35063  /*
35064  * Based on:
35065  * Ext JS Library 1.1.1
35066  * Copyright(c) 2006-2007, Ext JS, LLC.
35067  *
35068  * Originally Released Under LGPL - original licence link has changed is not relivant.
35069  *
35070  * Fork - LGPL
35071  * <script type="text/javascript">
35072  */
35073  
35074 /**
35075  * @class Roo.bootstrap.layout.Basic
35076  * @extends Roo.util.Observable
35077  * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35078  * and does not have a titlebar, tabs or any other features. All it does is size and position 
35079  * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35080  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35081  * @cfg {string}   region  the region that it inhabits..
35082  * @cfg {bool}   skipConfig skip config?
35083  * 
35084
35085  */
35086 Roo.bootstrap.layout.Basic = function(config){
35087     
35088     this.mgr = config.mgr;
35089     
35090     this.position = config.region;
35091     
35092     var skipConfig = config.skipConfig;
35093     
35094     this.events = {
35095         /**
35096          * @scope Roo.BasicLayoutRegion
35097          */
35098         
35099         /**
35100          * @event beforeremove
35101          * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35102          * @param {Roo.LayoutRegion} this
35103          * @param {Roo.ContentPanel} panel The panel
35104          * @param {Object} e The cancel event object
35105          */
35106         "beforeremove" : true,
35107         /**
35108          * @event invalidated
35109          * Fires when the layout for this region is changed.
35110          * @param {Roo.LayoutRegion} this
35111          */
35112         "invalidated" : true,
35113         /**
35114          * @event visibilitychange
35115          * Fires when this region is shown or hidden 
35116          * @param {Roo.LayoutRegion} this
35117          * @param {Boolean} visibility true or false
35118          */
35119         "visibilitychange" : true,
35120         /**
35121          * @event paneladded
35122          * Fires when a panel is added. 
35123          * @param {Roo.LayoutRegion} this
35124          * @param {Roo.ContentPanel} panel The panel
35125          */
35126         "paneladded" : true,
35127         /**
35128          * @event panelremoved
35129          * Fires when a panel is removed. 
35130          * @param {Roo.LayoutRegion} this
35131          * @param {Roo.ContentPanel} panel The panel
35132          */
35133         "panelremoved" : true,
35134         /**
35135          * @event beforecollapse
35136          * Fires when this region before collapse.
35137          * @param {Roo.LayoutRegion} this
35138          */
35139         "beforecollapse" : true,
35140         /**
35141          * @event collapsed
35142          * Fires when this region is collapsed.
35143          * @param {Roo.LayoutRegion} this
35144          */
35145         "collapsed" : true,
35146         /**
35147          * @event expanded
35148          * Fires when this region is expanded.
35149          * @param {Roo.LayoutRegion} this
35150          */
35151         "expanded" : true,
35152         /**
35153          * @event slideshow
35154          * Fires when this region is slid into view.
35155          * @param {Roo.LayoutRegion} this
35156          */
35157         "slideshow" : true,
35158         /**
35159          * @event slidehide
35160          * Fires when this region slides out of view. 
35161          * @param {Roo.LayoutRegion} this
35162          */
35163         "slidehide" : true,
35164         /**
35165          * @event panelactivated
35166          * Fires when a panel is activated. 
35167          * @param {Roo.LayoutRegion} this
35168          * @param {Roo.ContentPanel} panel The activated panel
35169          */
35170         "panelactivated" : true,
35171         /**
35172          * @event resized
35173          * Fires when the user resizes this region. 
35174          * @param {Roo.LayoutRegion} this
35175          * @param {Number} newSize The new size (width for east/west, height for north/south)
35176          */
35177         "resized" : true
35178     };
35179     /** A collection of panels in this region. @type Roo.util.MixedCollection */
35180     this.panels = new Roo.util.MixedCollection();
35181     this.panels.getKey = this.getPanelId.createDelegate(this);
35182     this.box = null;
35183     this.activePanel = null;
35184     // ensure listeners are added...
35185     
35186     if (config.listeners || config.events) {
35187         Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35188             listeners : config.listeners || {},
35189             events : config.events || {}
35190         });
35191     }
35192     
35193     if(skipConfig !== true){
35194         this.applyConfig(config);
35195     }
35196 };
35197
35198 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35199 {
35200     getPanelId : function(p){
35201         return p.getId();
35202     },
35203     
35204     applyConfig : function(config){
35205         this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35206         this.config = config;
35207         
35208     },
35209     
35210     /**
35211      * Resizes the region to the specified size. For vertical regions (west, east) this adjusts 
35212      * the width, for horizontal (north, south) the height.
35213      * @param {Number} newSize The new width or height
35214      */
35215     resizeTo : function(newSize){
35216         var el = this.el ? this.el :
35217                  (this.activePanel ? this.activePanel.getEl() : null);
35218         if(el){
35219             switch(this.position){
35220                 case "east":
35221                 case "west":
35222                     el.setWidth(newSize);
35223                     this.fireEvent("resized", this, newSize);
35224                 break;
35225                 case "north":
35226                 case "south":
35227                     el.setHeight(newSize);
35228                     this.fireEvent("resized", this, newSize);
35229                 break;                
35230             }
35231         }
35232     },
35233     
35234     getBox : function(){
35235         return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35236     },
35237     
35238     getMargins : function(){
35239         return this.margins;
35240     },
35241     
35242     updateBox : function(box){
35243         this.box = box;
35244         var el = this.activePanel.getEl();
35245         el.dom.style.left = box.x + "px";
35246         el.dom.style.top = box.y + "px";
35247         this.activePanel.setSize(box.width, box.height);
35248     },
35249     
35250     /**
35251      * Returns the container element for this region.
35252      * @return {Roo.Element}
35253      */
35254     getEl : function(){
35255         return this.activePanel;
35256     },
35257     
35258     /**
35259      * Returns true if this region is currently visible.
35260      * @return {Boolean}
35261      */
35262     isVisible : function(){
35263         return this.activePanel ? true : false;
35264     },
35265     
35266     setActivePanel : function(panel){
35267         panel = this.getPanel(panel);
35268         if(this.activePanel && this.activePanel != panel){
35269             this.activePanel.setActiveState(false);
35270             this.activePanel.getEl().setLeftTop(-10000,-10000);
35271         }
35272         this.activePanel = panel;
35273         panel.setActiveState(true);
35274         if(this.box){
35275             panel.setSize(this.box.width, this.box.height);
35276         }
35277         this.fireEvent("panelactivated", this, panel);
35278         this.fireEvent("invalidated");
35279     },
35280     
35281     /**
35282      * Show the specified panel.
35283      * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35284      * @return {Roo.ContentPanel} The shown panel or null
35285      */
35286     showPanel : function(panel){
35287         panel = this.getPanel(panel);
35288         if(panel){
35289             this.setActivePanel(panel);
35290         }
35291         return panel;
35292     },
35293     
35294     /**
35295      * Get the active panel for this region.
35296      * @return {Roo.ContentPanel} The active panel or null
35297      */
35298     getActivePanel : function(){
35299         return this.activePanel;
35300     },
35301     
35302     /**
35303      * Add the passed ContentPanel(s)
35304      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35305      * @return {Roo.ContentPanel} The panel added (if only one was added)
35306      */
35307     add : function(panel){
35308         if(arguments.length > 1){
35309             for(var i = 0, len = arguments.length; i < len; i++) {
35310                 this.add(arguments[i]);
35311             }
35312             return null;
35313         }
35314         if(this.hasPanel(panel)){
35315             this.showPanel(panel);
35316             return panel;
35317         }
35318         var el = panel.getEl();
35319         if(el.dom.parentNode != this.mgr.el.dom){
35320             this.mgr.el.dom.appendChild(el.dom);
35321         }
35322         if(panel.setRegion){
35323             panel.setRegion(this);
35324         }
35325         this.panels.add(panel);
35326         el.setStyle("position", "absolute");
35327         if(!panel.background){
35328             this.setActivePanel(panel);
35329             if(this.config.initialSize && this.panels.getCount()==1){
35330                 this.resizeTo(this.config.initialSize);
35331             }
35332         }
35333         this.fireEvent("paneladded", this, panel);
35334         return panel;
35335     },
35336     
35337     /**
35338      * Returns true if the panel is in this region.
35339      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35340      * @return {Boolean}
35341      */
35342     hasPanel : function(panel){
35343         if(typeof panel == "object"){ // must be panel obj
35344             panel = panel.getId();
35345         }
35346         return this.getPanel(panel) ? true : false;
35347     },
35348     
35349     /**
35350      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35351      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35352      * @param {Boolean} preservePanel Overrides the config preservePanel option
35353      * @return {Roo.ContentPanel} The panel that was removed
35354      */
35355     remove : function(panel, preservePanel){
35356         panel = this.getPanel(panel);
35357         if(!panel){
35358             return null;
35359         }
35360         var e = {};
35361         this.fireEvent("beforeremove", this, panel, e);
35362         if(e.cancel === true){
35363             return null;
35364         }
35365         var panelId = panel.getId();
35366         this.panels.removeKey(panelId);
35367         return panel;
35368     },
35369     
35370     /**
35371      * Returns the panel specified or null if it's not in this region.
35372      * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35373      * @return {Roo.ContentPanel}
35374      */
35375     getPanel : function(id){
35376         if(typeof id == "object"){ // must be panel obj
35377             return id;
35378         }
35379         return this.panels.get(id);
35380     },
35381     
35382     /**
35383      * Returns this regions position (north/south/east/west/center).
35384      * @return {String} 
35385      */
35386     getPosition: function(){
35387         return this.position;    
35388     }
35389 });/*
35390  * Based on:
35391  * Ext JS Library 1.1.1
35392  * Copyright(c) 2006-2007, Ext JS, LLC.
35393  *
35394  * Originally Released Under LGPL - original licence link has changed is not relivant.
35395  *
35396  * Fork - LGPL
35397  * <script type="text/javascript">
35398  */
35399  
35400 /**
35401  * @class Roo.bootstrap.layout.Region
35402  * @extends Roo.bootstrap.layout.Basic
35403  * This class represents a region in a layout manager.
35404  
35405  * @cfg {Object}    margins         Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35406  * @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})
35407  * @cfg {String}    tabPosition     (top|bottom) "top" or "bottom" (defaults to "bottom")
35408  * @cfg {Boolean}   alwaysShowTabs  True to always display tabs even when there is only 1 panel (defaults to false)
35409  * @cfg {Boolean}   autoScroll      True to enable overflow scrolling (defaults to false)
35410  * @cfg {Boolean}   titlebar        True to display a title bar (defaults to true)
35411  * @cfg {String}    title           The title for the region (overrides panel titles)
35412  * @cfg {Boolean}   animate         True to animate expand/collapse (defaults to false)
35413  * @cfg {Boolean}   autoHide        False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35414  * @cfg {Boolean}   preservePanels  True to preserve removed panels so they can be readded later (defaults to false)
35415  * @cfg {Boolean}   closeOnTab      True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35416  * @cfg {Boolean}   hideTabs        True to hide the tab strip (defaults to false)
35417  * @cfg {Boolean}   resizeTabs      True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35418  *                      the space available, similar to FireFox 1.5 tabs (defaults to false)
35419  * @cfg {Number}    minTabWidth     The minimum tab width (defaults to 40)
35420  * @cfg {Number}    preferredTabWidth The preferred tab width (defaults to 150)
35421  * @cfg {String}    overflow       (hidden|visible) if you have menus in the region, then you need to set this to visible.
35422
35423  * @cfg {Boolean}   hidden          True to start the region hidden (defaults to false)
35424  * @cfg {Boolean}   hideWhenEmpty   True to hide the region when it has no panels
35425  * @cfg {Boolean}   disableTabTips  True to disable tab tooltips
35426  * @cfg {Number}    width           For East/West panels
35427  * @cfg {Number}    height          For North/South panels
35428  * @cfg {Boolean}   split           To show the splitter
35429  * @cfg {Boolean}   toolbar         xtype configuration for a toolbar - shows on right of tabbar
35430  * 
35431  * @cfg {string}   cls             Extra CSS classes to add to region
35432  * 
35433  * @cfg {Roo.bootstrap.layout.Manager}   mgr The manager
35434  * @cfg {string}   region  the region that it inhabits..
35435  *
35436
35437  * @xxxcfg {Boolean}   collapsible     DISABLED False to disable collapsing (defaults to true)
35438  * @xxxcfg {Boolean}   collapsed       DISABLED True to set the initial display to collapsed (defaults to false)
35439
35440  * @xxxcfg {String}    collapsedTitle  DISABLED Optional string message to display in the collapsed block of a north or south region
35441  * @xxxxcfg {Boolean}   floatable       DISABLED False to disable floating (defaults to true)
35442  * @xxxxcfg {Boolean}   showPin         True to show a pin button NOT SUPPORTED YET
35443  */
35444 Roo.bootstrap.layout.Region = function(config)
35445 {
35446     this.applyConfig(config);
35447
35448     var mgr = config.mgr;
35449     var pos = config.region;
35450     config.skipConfig = true;
35451     Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35452     
35453     if (mgr.el) {
35454         this.onRender(mgr.el);   
35455     }
35456      
35457     this.visible = true;
35458     this.collapsed = false;
35459     this.unrendered_panels = [];
35460 };
35461
35462 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35463
35464     position: '', // set by wrapper (eg. north/south etc..)
35465     unrendered_panels : null,  // unrendered panels.
35466     createBody : function(){
35467         /** This region's body element 
35468         * @type Roo.Element */
35469         this.bodyEl = this.el.createChild({
35470                 tag: "div",
35471                 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35472         });
35473     },
35474
35475     onRender: function(ctr, pos)
35476     {
35477         var dh = Roo.DomHelper;
35478         /** This region's container element 
35479         * @type Roo.Element */
35480         this.el = dh.append(ctr.dom, {
35481                 tag: "div",
35482                 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35483             }, true);
35484         /** This region's title element 
35485         * @type Roo.Element */
35486     
35487         this.titleEl = dh.append(this.el.dom,
35488             {
35489                     tag: "div",
35490                     unselectable: "on",
35491                     cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35492                     children:[
35493                         {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: "&#160;"},
35494                         {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35495                     ]}, true);
35496         
35497         this.titleEl.enableDisplayMode();
35498         /** This region's title text element 
35499         * @type HTMLElement */
35500         this.titleTextEl = this.titleEl.dom.firstChild;
35501         this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35502         /*
35503         this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35504         this.closeBtn.enableDisplayMode();
35505         this.closeBtn.on("click", this.closeClicked, this);
35506         this.closeBtn.hide();
35507     */
35508         this.createBody(this.config);
35509         if(this.config.hideWhenEmpty){
35510             this.hide();
35511             this.on("paneladded", this.validateVisibility, this);
35512             this.on("panelremoved", this.validateVisibility, this);
35513         }
35514         if(this.autoScroll){
35515             this.bodyEl.setStyle("overflow", "auto");
35516         }else{
35517             this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35518         }
35519         //if(c.titlebar !== false){
35520             if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35521                 this.titleEl.hide();
35522             }else{
35523                 this.titleEl.show();
35524                 if(this.config.title){
35525                     this.titleTextEl.innerHTML = this.config.title;
35526                 }
35527             }
35528         //}
35529         if(this.config.collapsed){
35530             this.collapse(true);
35531         }
35532         if(this.config.hidden){
35533             this.hide();
35534         }
35535         
35536         if (this.unrendered_panels && this.unrendered_panels.length) {
35537             for (var i =0;i< this.unrendered_panels.length; i++) {
35538                 this.add(this.unrendered_panels[i]);
35539             }
35540             this.unrendered_panels = null;
35541             
35542         }
35543         
35544     },
35545     
35546     applyConfig : function(c)
35547     {
35548         /*
35549          *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35550             var dh = Roo.DomHelper;
35551             if(c.titlebar !== false){
35552                 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35553                 this.collapseBtn.on("click", this.collapse, this);
35554                 this.collapseBtn.enableDisplayMode();
35555                 /*
35556                 if(c.showPin === true || this.showPin){
35557                     this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35558                     this.stickBtn.enableDisplayMode();
35559                     this.stickBtn.on("click", this.expand, this);
35560                     this.stickBtn.hide();
35561                 }
35562                 
35563             }
35564             */
35565             /** This region's collapsed element
35566             * @type Roo.Element */
35567             /*
35568              *
35569             this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35570                 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35571             ]}, true);
35572             
35573             if(c.floatable !== false){
35574                this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35575                this.collapsedEl.on("click", this.collapseClick, this);
35576             }
35577
35578             if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35579                 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35580                    id: "message", unselectable: "on", style:{"float":"left"}});
35581                this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35582              }
35583             this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35584             this.expandBtn.on("click", this.expand, this);
35585             
35586         }
35587         
35588         if(this.collapseBtn){
35589             this.collapseBtn.setVisible(c.collapsible == true);
35590         }
35591         
35592         this.cmargins = c.cmargins || this.cmargins ||
35593                          (this.position == "west" || this.position == "east" ?
35594                              {top: 0, left: 2, right:2, bottom: 0} :
35595                              {top: 2, left: 0, right:0, bottom: 2});
35596         */
35597         this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35598         
35599         
35600         this.bottomTabs = c.tabPosition != "top";
35601         
35602         this.autoScroll = c.autoScroll || false;
35603         
35604         
35605        
35606         
35607         this.duration = c.duration || .30;
35608         this.slideDuration = c.slideDuration || .45;
35609         this.config = c;
35610        
35611     },
35612     /**
35613      * Returns true if this region is currently visible.
35614      * @return {Boolean}
35615      */
35616     isVisible : function(){
35617         return this.visible;
35618     },
35619
35620     /**
35621      * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35622      * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&amp;#160;")
35623      */
35624     //setCollapsedTitle : function(title){
35625     //    title = title || "&#160;";
35626      //   if(this.collapsedTitleTextEl){
35627       //      this.collapsedTitleTextEl.innerHTML = title;
35628        // }
35629     //},
35630
35631     getBox : function(){
35632         var b;
35633       //  if(!this.collapsed){
35634             b = this.el.getBox(false, true);
35635        // }else{
35636           //  b = this.collapsedEl.getBox(false, true);
35637         //}
35638         return b;
35639     },
35640
35641     getMargins : function(){
35642         return this.margins;
35643         //return this.collapsed ? this.cmargins : this.margins;
35644     },
35645 /*
35646     highlight : function(){
35647         this.el.addClass("x-layout-panel-dragover");
35648     },
35649
35650     unhighlight : function(){
35651         this.el.removeClass("x-layout-panel-dragover");
35652     },
35653 */
35654     updateBox : function(box)
35655     {
35656         if (!this.bodyEl) {
35657             return; // not rendered yet..
35658         }
35659         
35660         this.box = box;
35661         if(!this.collapsed){
35662             this.el.dom.style.left = box.x + "px";
35663             this.el.dom.style.top = box.y + "px";
35664             this.updateBody(box.width, box.height);
35665         }else{
35666             this.collapsedEl.dom.style.left = box.x + "px";
35667             this.collapsedEl.dom.style.top = box.y + "px";
35668             this.collapsedEl.setSize(box.width, box.height);
35669         }
35670         if(this.tabs){
35671             this.tabs.autoSizeTabs();
35672         }
35673     },
35674
35675     updateBody : function(w, h)
35676     {
35677         if(w !== null){
35678             this.el.setWidth(w);
35679             w -= this.el.getBorderWidth("rl");
35680             if(this.config.adjustments){
35681                 w += this.config.adjustments[0];
35682             }
35683         }
35684         if(h !== null && h > 0){
35685             this.el.setHeight(h);
35686             h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35687             h -= this.el.getBorderWidth("tb");
35688             if(this.config.adjustments){
35689                 h += this.config.adjustments[1];
35690             }
35691             this.bodyEl.setHeight(h);
35692             if(this.tabs){
35693                 h = this.tabs.syncHeight(h);
35694             }
35695         }
35696         if(this.panelSize){
35697             w = w !== null ? w : this.panelSize.width;
35698             h = h !== null ? h : this.panelSize.height;
35699         }
35700         if(this.activePanel){
35701             var el = this.activePanel.getEl();
35702             w = w !== null ? w : el.getWidth();
35703             h = h !== null ? h : el.getHeight();
35704             this.panelSize = {width: w, height: h};
35705             this.activePanel.setSize(w, h);
35706         }
35707         if(Roo.isIE && this.tabs){
35708             this.tabs.el.repaint();
35709         }
35710     },
35711
35712     /**
35713      * Returns the container element for this region.
35714      * @return {Roo.Element}
35715      */
35716     getEl : function(){
35717         return this.el;
35718     },
35719
35720     /**
35721      * Hides this region.
35722      */
35723     hide : function(){
35724         //if(!this.collapsed){
35725             this.el.dom.style.left = "-2000px";
35726             this.el.hide();
35727         //}else{
35728          //   this.collapsedEl.dom.style.left = "-2000px";
35729          //   this.collapsedEl.hide();
35730        // }
35731         this.visible = false;
35732         this.fireEvent("visibilitychange", this, false);
35733     },
35734
35735     /**
35736      * Shows this region if it was previously hidden.
35737      */
35738     show : function(){
35739         //if(!this.collapsed){
35740             this.el.show();
35741         //}else{
35742         //    this.collapsedEl.show();
35743        // }
35744         this.visible = true;
35745         this.fireEvent("visibilitychange", this, true);
35746     },
35747 /*
35748     closeClicked : function(){
35749         if(this.activePanel){
35750             this.remove(this.activePanel);
35751         }
35752     },
35753
35754     collapseClick : function(e){
35755         if(this.isSlid){
35756            e.stopPropagation();
35757            this.slideIn();
35758         }else{
35759            e.stopPropagation();
35760            this.slideOut();
35761         }
35762     },
35763 */
35764     /**
35765      * Collapses this region.
35766      * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
35767      */
35768     /*
35769     collapse : function(skipAnim, skipCheck = false){
35770         if(this.collapsed) {
35771             return;
35772         }
35773         
35774         if(skipCheck || this.fireEvent("beforecollapse", this) != false){
35775             
35776             this.collapsed = true;
35777             if(this.split){
35778                 this.split.el.hide();
35779             }
35780             if(this.config.animate && skipAnim !== true){
35781                 this.fireEvent("invalidated", this);
35782                 this.animateCollapse();
35783             }else{
35784                 this.el.setLocation(-20000,-20000);
35785                 this.el.hide();
35786                 this.collapsedEl.show();
35787                 this.fireEvent("collapsed", this);
35788                 this.fireEvent("invalidated", this);
35789             }
35790         }
35791         
35792     },
35793 */
35794     animateCollapse : function(){
35795         // overridden
35796     },
35797
35798     /**
35799      * Expands this region if it was previously collapsed.
35800      * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
35801      * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
35802      */
35803     /*
35804     expand : function(e, skipAnim){
35805         if(e) {
35806             e.stopPropagation();
35807         }
35808         if(!this.collapsed || this.el.hasActiveFx()) {
35809             return;
35810         }
35811         if(this.isSlid){
35812             this.afterSlideIn();
35813             skipAnim = true;
35814         }
35815         this.collapsed = false;
35816         if(this.config.animate && skipAnim !== true){
35817             this.animateExpand();
35818         }else{
35819             this.el.show();
35820             if(this.split){
35821                 this.split.el.show();
35822             }
35823             this.collapsedEl.setLocation(-2000,-2000);
35824             this.collapsedEl.hide();
35825             this.fireEvent("invalidated", this);
35826             this.fireEvent("expanded", this);
35827         }
35828     },
35829 */
35830     animateExpand : function(){
35831         // overridden
35832     },
35833
35834     initTabs : function()
35835     {
35836         //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
35837         
35838         var ts = new Roo.bootstrap.panel.Tabs({
35839                 el: this.bodyEl.dom,
35840                 tabPosition: this.bottomTabs ? 'bottom' : 'top',
35841                 disableTooltips: this.config.disableTabTips,
35842                 toolbar : this.config.toolbar
35843             });
35844         
35845         if(this.config.hideTabs){
35846             ts.stripWrap.setDisplayed(false);
35847         }
35848         this.tabs = ts;
35849         ts.resizeTabs = this.config.resizeTabs === true;
35850         ts.minTabWidth = this.config.minTabWidth || 40;
35851         ts.maxTabWidth = this.config.maxTabWidth || 250;
35852         ts.preferredTabWidth = this.config.preferredTabWidth || 150;
35853         ts.monitorResize = false;
35854         //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
35855         ts.bodyEl.addClass('roo-layout-tabs-body');
35856         this.panels.each(this.initPanelAsTab, this);
35857     },
35858
35859     initPanelAsTab : function(panel){
35860         var ti = this.tabs.addTab(
35861             panel.getEl().id,
35862             panel.getTitle(),
35863             null,
35864             this.config.closeOnTab && panel.isClosable(),
35865             panel.tpl
35866         );
35867         if(panel.tabTip !== undefined){
35868             ti.setTooltip(panel.tabTip);
35869         }
35870         ti.on("activate", function(){
35871               this.setActivePanel(panel);
35872         }, this);
35873         
35874         if(this.config.closeOnTab){
35875             ti.on("beforeclose", function(t, e){
35876                 e.cancel = true;
35877                 this.remove(panel);
35878             }, this);
35879         }
35880         
35881         panel.tabItem = ti;
35882         
35883         return ti;
35884     },
35885
35886     updatePanelTitle : function(panel, title)
35887     {
35888         if(this.activePanel == panel){
35889             this.updateTitle(title);
35890         }
35891         if(this.tabs){
35892             var ti = this.tabs.getTab(panel.getEl().id);
35893             ti.setText(title);
35894             if(panel.tabTip !== undefined){
35895                 ti.setTooltip(panel.tabTip);
35896             }
35897         }
35898     },
35899
35900     updateTitle : function(title){
35901         if(this.titleTextEl && !this.config.title){
35902             this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : "&#160;");
35903         }
35904     },
35905
35906     setActivePanel : function(panel)
35907     {
35908         panel = this.getPanel(panel);
35909         if(this.activePanel && this.activePanel != panel){
35910             if(this.activePanel.setActiveState(false) === false){
35911                 return;
35912             }
35913         }
35914         this.activePanel = panel;
35915         panel.setActiveState(true);
35916         if(this.panelSize){
35917             panel.setSize(this.panelSize.width, this.panelSize.height);
35918         }
35919         if(this.closeBtn){
35920             this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
35921         }
35922         this.updateTitle(panel.getTitle());
35923         if(this.tabs){
35924             this.fireEvent("invalidated", this);
35925         }
35926         this.fireEvent("panelactivated", this, panel);
35927     },
35928
35929     /**
35930      * Shows the specified panel.
35931      * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
35932      * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
35933      */
35934     showPanel : function(panel)
35935     {
35936         panel = this.getPanel(panel);
35937         if(panel){
35938             if(this.tabs){
35939                 var tab = this.tabs.getTab(panel.getEl().id);
35940                 if(tab.isHidden()){
35941                     this.tabs.unhideTab(tab.id);
35942                 }
35943                 tab.activate();
35944             }else{
35945                 this.setActivePanel(panel);
35946             }
35947         }
35948         return panel;
35949     },
35950
35951     /**
35952      * Get the active panel for this region.
35953      * @return {Roo.ContentPanel} The active panel or null
35954      */
35955     getActivePanel : function(){
35956         return this.activePanel;
35957     },
35958
35959     validateVisibility : function(){
35960         if(this.panels.getCount() < 1){
35961             this.updateTitle("&#160;");
35962             this.closeBtn.hide();
35963             this.hide();
35964         }else{
35965             if(!this.isVisible()){
35966                 this.show();
35967             }
35968         }
35969     },
35970
35971     /**
35972      * Adds the passed ContentPanel(s) to this region.
35973      * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35974      * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
35975      */
35976     add : function(panel)
35977     {
35978         if(arguments.length > 1){
35979             for(var i = 0, len = arguments.length; i < len; i++) {
35980                 this.add(arguments[i]);
35981             }
35982             return null;
35983         }
35984         
35985         // if we have not been rendered yet, then we can not really do much of this..
35986         if (!this.bodyEl) {
35987             this.unrendered_panels.push(panel);
35988             return panel;
35989         }
35990         
35991         
35992         
35993         
35994         if(this.hasPanel(panel)){
35995             this.showPanel(panel);
35996             return panel;
35997         }
35998         panel.setRegion(this);
35999         this.panels.add(panel);
36000        /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36001             // sinle panel - no tab...?? would it not be better to render it with the tabs,
36002             // and hide them... ???
36003             this.bodyEl.dom.appendChild(panel.getEl().dom);
36004             if(panel.background !== true){
36005                 this.setActivePanel(panel);
36006             }
36007             this.fireEvent("paneladded", this, panel);
36008             return panel;
36009         }
36010         */
36011         if(!this.tabs){
36012             this.initTabs();
36013         }else{
36014             this.initPanelAsTab(panel);
36015         }
36016         
36017         
36018         if(panel.background !== true){
36019             this.tabs.activate(panel.getEl().id);
36020         }
36021         this.fireEvent("paneladded", this, panel);
36022         return panel;
36023     },
36024
36025     /**
36026      * Hides the tab for the specified panel.
36027      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36028      */
36029     hidePanel : function(panel){
36030         if(this.tabs && (panel = this.getPanel(panel))){
36031             this.tabs.hideTab(panel.getEl().id);
36032         }
36033     },
36034
36035     /**
36036      * Unhides the tab for a previously hidden panel.
36037      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36038      */
36039     unhidePanel : function(panel){
36040         if(this.tabs && (panel = this.getPanel(panel))){
36041             this.tabs.unhideTab(panel.getEl().id);
36042         }
36043     },
36044
36045     clearPanels : function(){
36046         while(this.panels.getCount() > 0){
36047              this.remove(this.panels.first());
36048         }
36049     },
36050
36051     /**
36052      * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36053      * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36054      * @param {Boolean} preservePanel Overrides the config preservePanel option
36055      * @return {Roo.ContentPanel} The panel that was removed
36056      */
36057     remove : function(panel, preservePanel)
36058     {
36059         panel = this.getPanel(panel);
36060         if(!panel){
36061             return null;
36062         }
36063         var e = {};
36064         this.fireEvent("beforeremove", this, panel, e);
36065         if(e.cancel === true){
36066             return null;
36067         }
36068         preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36069         var panelId = panel.getId();
36070         this.panels.removeKey(panelId);
36071         if(preservePanel){
36072             document.body.appendChild(panel.getEl().dom);
36073         }
36074         if(this.tabs){
36075             this.tabs.removeTab(panel.getEl().id);
36076         }else if (!preservePanel){
36077             this.bodyEl.dom.removeChild(panel.getEl().dom);
36078         }
36079         if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36080             var p = this.panels.first();
36081             var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36082             tempEl.appendChild(p.getEl().dom);
36083             this.bodyEl.update("");
36084             this.bodyEl.dom.appendChild(p.getEl().dom);
36085             tempEl = null;
36086             this.updateTitle(p.getTitle());
36087             this.tabs = null;
36088             this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36089             this.setActivePanel(p);
36090         }
36091         panel.setRegion(null);
36092         if(this.activePanel == panel){
36093             this.activePanel = null;
36094         }
36095         if(this.config.autoDestroy !== false && preservePanel !== true){
36096             try{panel.destroy();}catch(e){}
36097         }
36098         this.fireEvent("panelremoved", this, panel);
36099         return panel;
36100     },
36101
36102     /**
36103      * Returns the TabPanel component used by this region
36104      * @return {Roo.TabPanel}
36105      */
36106     getTabs : function(){
36107         return this.tabs;
36108     },
36109
36110     createTool : function(parentEl, className){
36111         var btn = Roo.DomHelper.append(parentEl, {
36112             tag: "div",
36113             cls: "x-layout-tools-button",
36114             children: [ {
36115                 tag: "div",
36116                 cls: "roo-layout-tools-button-inner " + className,
36117                 html: "&#160;"
36118             }]
36119         }, true);
36120         btn.addClassOnOver("roo-layout-tools-button-over");
36121         return btn;
36122     }
36123 });/*
36124  * Based on:
36125  * Ext JS Library 1.1.1
36126  * Copyright(c) 2006-2007, Ext JS, LLC.
36127  *
36128  * Originally Released Under LGPL - original licence link has changed is not relivant.
36129  *
36130  * Fork - LGPL
36131  * <script type="text/javascript">
36132  */
36133  
36134
36135
36136 /**
36137  * @class Roo.SplitLayoutRegion
36138  * @extends Roo.LayoutRegion
36139  * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36140  */
36141 Roo.bootstrap.layout.Split = function(config){
36142     this.cursor = config.cursor;
36143     Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36144 };
36145
36146 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36147 {
36148     splitTip : "Drag to resize.",
36149     collapsibleSplitTip : "Drag to resize. Double click to hide.",
36150     useSplitTips : false,
36151
36152     applyConfig : function(config){
36153         Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36154     },
36155     
36156     onRender : function(ctr,pos) {
36157         
36158         Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36159         if(!this.config.split){
36160             return;
36161         }
36162         if(!this.split){
36163             
36164             var splitEl = Roo.DomHelper.append(ctr.dom,  {
36165                             tag: "div",
36166                             id: this.el.id + "-split",
36167                             cls: "roo-layout-split roo-layout-split-"+this.position,
36168                             html: "&#160;"
36169             });
36170             /** The SplitBar for this region 
36171             * @type Roo.SplitBar */
36172             // does not exist yet...
36173             Roo.log([this.position, this.orientation]);
36174             
36175             this.split = new Roo.bootstrap.SplitBar({
36176                 dragElement : splitEl,
36177                 resizingElement: this.el,
36178                 orientation : this.orientation
36179             });
36180             
36181             this.split.on("moved", this.onSplitMove, this);
36182             this.split.useShim = this.config.useShim === true;
36183             this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36184             if(this.useSplitTips){
36185                 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36186             }
36187             //if(config.collapsible){
36188             //    this.split.el.on("dblclick", this.collapse,  this);
36189             //}
36190         }
36191         if(typeof this.config.minSize != "undefined"){
36192             this.split.minSize = this.config.minSize;
36193         }
36194         if(typeof this.config.maxSize != "undefined"){
36195             this.split.maxSize = this.config.maxSize;
36196         }
36197         if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36198             this.hideSplitter();
36199         }
36200         
36201     },
36202
36203     getHMaxSize : function(){
36204          var cmax = this.config.maxSize || 10000;
36205          var center = this.mgr.getRegion("center");
36206          return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36207     },
36208
36209     getVMaxSize : function(){
36210          var cmax = this.config.maxSize || 10000;
36211          var center = this.mgr.getRegion("center");
36212          return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36213     },
36214
36215     onSplitMove : function(split, newSize){
36216         this.fireEvent("resized", this, newSize);
36217     },
36218     
36219     /** 
36220      * Returns the {@link Roo.SplitBar} for this region.
36221      * @return {Roo.SplitBar}
36222      */
36223     getSplitBar : function(){
36224         return this.split;
36225     },
36226     
36227     hide : function(){
36228         this.hideSplitter();
36229         Roo.bootstrap.layout.Split.superclass.hide.call(this);
36230     },
36231
36232     hideSplitter : function(){
36233         if(this.split){
36234             this.split.el.setLocation(-2000,-2000);
36235             this.split.el.hide();
36236         }
36237     },
36238
36239     show : function(){
36240         if(this.split){
36241             this.split.el.show();
36242         }
36243         Roo.bootstrap.layout.Split.superclass.show.call(this);
36244     },
36245     
36246     beforeSlide: function(){
36247         if(Roo.isGecko){// firefox overflow auto bug workaround
36248             this.bodyEl.clip();
36249             if(this.tabs) {
36250                 this.tabs.bodyEl.clip();
36251             }
36252             if(this.activePanel){
36253                 this.activePanel.getEl().clip();
36254                 
36255                 if(this.activePanel.beforeSlide){
36256                     this.activePanel.beforeSlide();
36257                 }
36258             }
36259         }
36260     },
36261     
36262     afterSlide : function(){
36263         if(Roo.isGecko){// firefox overflow auto bug workaround
36264             this.bodyEl.unclip();
36265             if(this.tabs) {
36266                 this.tabs.bodyEl.unclip();
36267             }
36268             if(this.activePanel){
36269                 this.activePanel.getEl().unclip();
36270                 if(this.activePanel.afterSlide){
36271                     this.activePanel.afterSlide();
36272                 }
36273             }
36274         }
36275     },
36276
36277     initAutoHide : function(){
36278         if(this.autoHide !== false){
36279             if(!this.autoHideHd){
36280                 var st = new Roo.util.DelayedTask(this.slideIn, this);
36281                 this.autoHideHd = {
36282                     "mouseout": function(e){
36283                         if(!e.within(this.el, true)){
36284                             st.delay(500);
36285                         }
36286                     },
36287                     "mouseover" : function(e){
36288                         st.cancel();
36289                     },
36290                     scope : this
36291                 };
36292             }
36293             this.el.on(this.autoHideHd);
36294         }
36295     },
36296
36297     clearAutoHide : function(){
36298         if(this.autoHide !== false){
36299             this.el.un("mouseout", this.autoHideHd.mouseout);
36300             this.el.un("mouseover", this.autoHideHd.mouseover);
36301         }
36302     },
36303
36304     clearMonitor : function(){
36305         Roo.get(document).un("click", this.slideInIf, this);
36306     },
36307
36308     // these names are backwards but not changed for compat
36309     slideOut : function(){
36310         if(this.isSlid || this.el.hasActiveFx()){
36311             return;
36312         }
36313         this.isSlid = true;
36314         if(this.collapseBtn){
36315             this.collapseBtn.hide();
36316         }
36317         this.closeBtnState = this.closeBtn.getStyle('display');
36318         this.closeBtn.hide();
36319         if(this.stickBtn){
36320             this.stickBtn.show();
36321         }
36322         this.el.show();
36323         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36324         this.beforeSlide();
36325         this.el.setStyle("z-index", 10001);
36326         this.el.slideIn(this.getSlideAnchor(), {
36327             callback: function(){
36328                 this.afterSlide();
36329                 this.initAutoHide();
36330                 Roo.get(document).on("click", this.slideInIf, this);
36331                 this.fireEvent("slideshow", this);
36332             },
36333             scope: this,
36334             block: true
36335         });
36336     },
36337
36338     afterSlideIn : function(){
36339         this.clearAutoHide();
36340         this.isSlid = false;
36341         this.clearMonitor();
36342         this.el.setStyle("z-index", "");
36343         if(this.collapseBtn){
36344             this.collapseBtn.show();
36345         }
36346         this.closeBtn.setStyle('display', this.closeBtnState);
36347         if(this.stickBtn){
36348             this.stickBtn.hide();
36349         }
36350         this.fireEvent("slidehide", this);
36351     },
36352
36353     slideIn : function(cb){
36354         if(!this.isSlid || this.el.hasActiveFx()){
36355             Roo.callback(cb);
36356             return;
36357         }
36358         this.isSlid = false;
36359         this.beforeSlide();
36360         this.el.slideOut(this.getSlideAnchor(), {
36361             callback: function(){
36362                 this.el.setLeftTop(-10000, -10000);
36363                 this.afterSlide();
36364                 this.afterSlideIn();
36365                 Roo.callback(cb);
36366             },
36367             scope: this,
36368             block: true
36369         });
36370     },
36371     
36372     slideInIf : function(e){
36373         if(!e.within(this.el)){
36374             this.slideIn();
36375         }
36376     },
36377
36378     animateCollapse : function(){
36379         this.beforeSlide();
36380         this.el.setStyle("z-index", 20000);
36381         var anchor = this.getSlideAnchor();
36382         this.el.slideOut(anchor, {
36383             callback : function(){
36384                 this.el.setStyle("z-index", "");
36385                 this.collapsedEl.slideIn(anchor, {duration:.3});
36386                 this.afterSlide();
36387                 this.el.setLocation(-10000,-10000);
36388                 this.el.hide();
36389                 this.fireEvent("collapsed", this);
36390             },
36391             scope: this,
36392             block: true
36393         });
36394     },
36395
36396     animateExpand : function(){
36397         this.beforeSlide();
36398         this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36399         this.el.setStyle("z-index", 20000);
36400         this.collapsedEl.hide({
36401             duration:.1
36402         });
36403         this.el.slideIn(this.getSlideAnchor(), {
36404             callback : function(){
36405                 this.el.setStyle("z-index", "");
36406                 this.afterSlide();
36407                 if(this.split){
36408                     this.split.el.show();
36409                 }
36410                 this.fireEvent("invalidated", this);
36411                 this.fireEvent("expanded", this);
36412             },
36413             scope: this,
36414             block: true
36415         });
36416     },
36417
36418     anchors : {
36419         "west" : "left",
36420         "east" : "right",
36421         "north" : "top",
36422         "south" : "bottom"
36423     },
36424
36425     sanchors : {
36426         "west" : "l",
36427         "east" : "r",
36428         "north" : "t",
36429         "south" : "b"
36430     },
36431
36432     canchors : {
36433         "west" : "tl-tr",
36434         "east" : "tr-tl",
36435         "north" : "tl-bl",
36436         "south" : "bl-tl"
36437     },
36438
36439     getAnchor : function(){
36440         return this.anchors[this.position];
36441     },
36442
36443     getCollapseAnchor : function(){
36444         return this.canchors[this.position];
36445     },
36446
36447     getSlideAnchor : function(){
36448         return this.sanchors[this.position];
36449     },
36450
36451     getAlignAdj : function(){
36452         var cm = this.cmargins;
36453         switch(this.position){
36454             case "west":
36455                 return [0, 0];
36456             break;
36457             case "east":
36458                 return [0, 0];
36459             break;
36460             case "north":
36461                 return [0, 0];
36462             break;
36463             case "south":
36464                 return [0, 0];
36465             break;
36466         }
36467     },
36468
36469     getExpandAdj : function(){
36470         var c = this.collapsedEl, cm = this.cmargins;
36471         switch(this.position){
36472             case "west":
36473                 return [-(cm.right+c.getWidth()+cm.left), 0];
36474             break;
36475             case "east":
36476                 return [cm.right+c.getWidth()+cm.left, 0];
36477             break;
36478             case "north":
36479                 return [0, -(cm.top+cm.bottom+c.getHeight())];
36480             break;
36481             case "south":
36482                 return [0, cm.top+cm.bottom+c.getHeight()];
36483             break;
36484         }
36485     }
36486 });/*
36487  * Based on:
36488  * Ext JS Library 1.1.1
36489  * Copyright(c) 2006-2007, Ext JS, LLC.
36490  *
36491  * Originally Released Under LGPL - original licence link has changed is not relivant.
36492  *
36493  * Fork - LGPL
36494  * <script type="text/javascript">
36495  */
36496 /*
36497  * These classes are private internal classes
36498  */
36499 Roo.bootstrap.layout.Center = function(config){
36500     config.region = "center";
36501     Roo.bootstrap.layout.Region.call(this, config);
36502     this.visible = true;
36503     this.minWidth = config.minWidth || 20;
36504     this.minHeight = config.minHeight || 20;
36505 };
36506
36507 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36508     hide : function(){
36509         // center panel can't be hidden
36510     },
36511     
36512     show : function(){
36513         // center panel can't be hidden
36514     },
36515     
36516     getMinWidth: function(){
36517         return this.minWidth;
36518     },
36519     
36520     getMinHeight: function(){
36521         return this.minHeight;
36522     }
36523 });
36524
36525
36526
36527
36528  
36529
36530
36531
36532
36533
36534 Roo.bootstrap.layout.North = function(config)
36535 {
36536     config.region = 'north';
36537     config.cursor = 'n-resize';
36538     
36539     Roo.bootstrap.layout.Split.call(this, config);
36540     
36541     
36542     if(this.split){
36543         this.split.placement = Roo.bootstrap.SplitBar.TOP;
36544         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36545         this.split.el.addClass("roo-layout-split-v");
36546     }
36547     var size = config.initialSize || config.height;
36548     if(typeof size != "undefined"){
36549         this.el.setHeight(size);
36550     }
36551 };
36552 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36553 {
36554     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36555     
36556     
36557     
36558     getBox : function(){
36559         if(this.collapsed){
36560             return this.collapsedEl.getBox();
36561         }
36562         var box = this.el.getBox();
36563         if(this.split){
36564             box.height += this.split.el.getHeight();
36565         }
36566         return box;
36567     },
36568     
36569     updateBox : function(box){
36570         if(this.split && !this.collapsed){
36571             box.height -= this.split.el.getHeight();
36572             this.split.el.setLeft(box.x);
36573             this.split.el.setTop(box.y+box.height);
36574             this.split.el.setWidth(box.width);
36575         }
36576         if(this.collapsed){
36577             this.updateBody(box.width, null);
36578         }
36579         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36580     }
36581 });
36582
36583
36584
36585
36586
36587 Roo.bootstrap.layout.South = function(config){
36588     config.region = 'south';
36589     config.cursor = 's-resize';
36590     Roo.bootstrap.layout.Split.call(this, config);
36591     if(this.split){
36592         this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36593         this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36594         this.split.el.addClass("roo-layout-split-v");
36595     }
36596     var size = config.initialSize || config.height;
36597     if(typeof size != "undefined"){
36598         this.el.setHeight(size);
36599     }
36600 };
36601
36602 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36603     orientation: Roo.bootstrap.SplitBar.VERTICAL,
36604     getBox : function(){
36605         if(this.collapsed){
36606             return this.collapsedEl.getBox();
36607         }
36608         var box = this.el.getBox();
36609         if(this.split){
36610             var sh = this.split.el.getHeight();
36611             box.height += sh;
36612             box.y -= sh;
36613         }
36614         return box;
36615     },
36616     
36617     updateBox : function(box){
36618         if(this.split && !this.collapsed){
36619             var sh = this.split.el.getHeight();
36620             box.height -= sh;
36621             box.y += sh;
36622             this.split.el.setLeft(box.x);
36623             this.split.el.setTop(box.y-sh);
36624             this.split.el.setWidth(box.width);
36625         }
36626         if(this.collapsed){
36627             this.updateBody(box.width, null);
36628         }
36629         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36630     }
36631 });
36632
36633 Roo.bootstrap.layout.East = function(config){
36634     config.region = "east";
36635     config.cursor = "e-resize";
36636     Roo.bootstrap.layout.Split.call(this, config);
36637     if(this.split){
36638         this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36639         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36640         this.split.el.addClass("roo-layout-split-h");
36641     }
36642     var size = config.initialSize || config.width;
36643     if(typeof size != "undefined"){
36644         this.el.setWidth(size);
36645     }
36646 };
36647 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36648     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36649     getBox : function(){
36650         if(this.collapsed){
36651             return this.collapsedEl.getBox();
36652         }
36653         var box = this.el.getBox();
36654         if(this.split){
36655             var sw = this.split.el.getWidth();
36656             box.width += sw;
36657             box.x -= sw;
36658         }
36659         return box;
36660     },
36661
36662     updateBox : function(box){
36663         if(this.split && !this.collapsed){
36664             var sw = this.split.el.getWidth();
36665             box.width -= sw;
36666             this.split.el.setLeft(box.x);
36667             this.split.el.setTop(box.y);
36668             this.split.el.setHeight(box.height);
36669             box.x += sw;
36670         }
36671         if(this.collapsed){
36672             this.updateBody(null, box.height);
36673         }
36674         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36675     }
36676 });
36677
36678 Roo.bootstrap.layout.West = function(config){
36679     config.region = "west";
36680     config.cursor = "w-resize";
36681     
36682     Roo.bootstrap.layout.Split.call(this, config);
36683     if(this.split){
36684         this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36685         this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36686         this.split.el.addClass("roo-layout-split-h");
36687     }
36688     
36689 };
36690 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36691     orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36692     
36693     onRender: function(ctr, pos)
36694     {
36695         Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36696         var size = this.config.initialSize || this.config.width;
36697         if(typeof size != "undefined"){
36698             this.el.setWidth(size);
36699         }
36700     },
36701     
36702     getBox : function(){
36703         if(this.collapsed){
36704             return this.collapsedEl.getBox();
36705         }
36706         var box = this.el.getBox();
36707         if(this.split){
36708             box.width += this.split.el.getWidth();
36709         }
36710         return box;
36711     },
36712     
36713     updateBox : function(box){
36714         if(this.split && !this.collapsed){
36715             var sw = this.split.el.getWidth();
36716             box.width -= sw;
36717             this.split.el.setLeft(box.x+box.width);
36718             this.split.el.setTop(box.y);
36719             this.split.el.setHeight(box.height);
36720         }
36721         if(this.collapsed){
36722             this.updateBody(null, box.height);
36723         }
36724         Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36725     }
36726 });
36727 Roo.namespace("Roo.bootstrap.panel");/*
36728  * Based on:
36729  * Ext JS Library 1.1.1
36730  * Copyright(c) 2006-2007, Ext JS, LLC.
36731  *
36732  * Originally Released Under LGPL - original licence link has changed is not relivant.
36733  *
36734  * Fork - LGPL
36735  * <script type="text/javascript">
36736  */
36737 /**
36738  * @class Roo.ContentPanel
36739  * @extends Roo.util.Observable
36740  * A basic ContentPanel element.
36741  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
36742  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
36743  * @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
36744  * @cfg {Boolean}   closable      True if the panel can be closed/removed
36745  * @cfg {Boolean}   background    True if the panel should not be activated when it is added (defaults to false)
36746  * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
36747  * @cfg {Toolbar}   toolbar       A toolbar for this panel
36748  * @cfg {Boolean} autoScroll    True to scroll overflow in this panel (use with {@link #fitToFrame})
36749  * @cfg {String} title          The title for this panel
36750  * @cfg {Array} adjustments     Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
36751  * @cfg {String} url            Calls {@link #setUrl} with this value
36752  * @cfg {String} region         (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
36753  * @cfg {String/Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
36754  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
36755  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
36756  * @cfg {Boolean} badges render the badges
36757
36758  * @constructor
36759  * Create a new ContentPanel.
36760  * @param {String/HTMLElement/Roo.Element} el The container element for this panel
36761  * @param {String/Object} config A string to set only the title or a config object
36762  * @param {String} content (optional) Set the HTML content for this panel
36763  * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
36764  */
36765 Roo.bootstrap.panel.Content = function( config){
36766     
36767     this.tpl = config.tpl || false;
36768     
36769     var el = config.el;
36770     var content = config.content;
36771
36772     if(config.autoCreate){ // xtype is available if this is called from factory
36773         el = Roo.id();
36774     }
36775     this.el = Roo.get(el);
36776     if(!this.el && config && config.autoCreate){
36777         if(typeof config.autoCreate == "object"){
36778             if(!config.autoCreate.id){
36779                 config.autoCreate.id = config.id||el;
36780             }
36781             this.el = Roo.DomHelper.append(document.body,
36782                         config.autoCreate, true);
36783         }else{
36784             var elcfg =  {   tag: "div",
36785                             cls: "roo-layout-inactive-content",
36786                             id: config.id||el
36787                             };
36788             if (config.html) {
36789                 elcfg.html = config.html;
36790                 
36791             }
36792                         
36793             this.el = Roo.DomHelper.append(document.body, elcfg , true);
36794         }
36795     } 
36796     this.closable = false;
36797     this.loaded = false;
36798     this.active = false;
36799    
36800       
36801     if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
36802         
36803         this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
36804         
36805         this.wrapEl = this.el; //this.el.wrap();
36806         var ti = [];
36807         if (config.toolbar.items) {
36808             ti = config.toolbar.items ;
36809             delete config.toolbar.items ;
36810         }
36811         
36812         var nitems = [];
36813         this.toolbar.render(this.wrapEl, 'before');
36814         for(var i =0;i < ti.length;i++) {
36815           //  Roo.log(['add child', items[i]]);
36816             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
36817         }
36818         this.toolbar.items = nitems;
36819         this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
36820         delete config.toolbar;
36821         
36822     }
36823     /*
36824     // xtype created footer. - not sure if will work as we normally have to render first..
36825     if (this.footer && !this.footer.el && this.footer.xtype) {
36826         if (!this.wrapEl) {
36827             this.wrapEl = this.el.wrap();
36828         }
36829     
36830         this.footer.container = this.wrapEl.createChild();
36831          
36832         this.footer = Roo.factory(this.footer, Roo);
36833         
36834     }
36835     */
36836     
36837      if(typeof config == "string"){
36838         this.title = config;
36839     }else{
36840         Roo.apply(this, config);
36841     }
36842     
36843     if(this.resizeEl){
36844         this.resizeEl = Roo.get(this.resizeEl, true);
36845     }else{
36846         this.resizeEl = this.el;
36847     }
36848     // handle view.xtype
36849     
36850  
36851     
36852     
36853     this.addEvents({
36854         /**
36855          * @event activate
36856          * Fires when this panel is activated. 
36857          * @param {Roo.ContentPanel} this
36858          */
36859         "activate" : true,
36860         /**
36861          * @event deactivate
36862          * Fires when this panel is activated. 
36863          * @param {Roo.ContentPanel} this
36864          */
36865         "deactivate" : true,
36866
36867         /**
36868          * @event resize
36869          * Fires when this panel is resized if fitToFrame is true.
36870          * @param {Roo.ContentPanel} this
36871          * @param {Number} width The width after any component adjustments
36872          * @param {Number} height The height after any component adjustments
36873          */
36874         "resize" : true,
36875         
36876          /**
36877          * @event render
36878          * Fires when this tab is created
36879          * @param {Roo.ContentPanel} this
36880          */
36881         "render" : true
36882         
36883         
36884         
36885     });
36886     
36887
36888     
36889     
36890     if(this.autoScroll){
36891         this.resizeEl.setStyle("overflow", "auto");
36892     } else {
36893         // fix randome scrolling
36894         //this.el.on('scroll', function() {
36895         //    Roo.log('fix random scolling');
36896         //    this.scrollTo('top',0); 
36897         //});
36898     }
36899     content = content || this.content;
36900     if(content){
36901         this.setContent(content);
36902     }
36903     if(config && config.url){
36904         this.setUrl(this.url, this.params, this.loadOnce);
36905     }
36906     
36907     
36908     
36909     Roo.bootstrap.panel.Content.superclass.constructor.call(this);
36910     
36911     if (this.view && typeof(this.view.xtype) != 'undefined') {
36912         this.view.el = this.el.appendChild(document.createElement("div"));
36913         this.view = Roo.factory(this.view); 
36914         this.view.render  &&  this.view.render(false, '');  
36915     }
36916     
36917     
36918     this.fireEvent('render', this);
36919 };
36920
36921 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
36922     
36923     tabTip : '',
36924     
36925     setRegion : function(region){
36926         this.region = region;
36927         this.setActiveClass(region && !this.background);
36928     },
36929     
36930     
36931     setActiveClass: function(state)
36932     {
36933         if(state){
36934            this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
36935            this.el.setStyle('position','relative');
36936         }else{
36937            this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
36938            this.el.setStyle('position', 'absolute');
36939         } 
36940     },
36941     
36942     /**
36943      * Returns the toolbar for this Panel if one was configured. 
36944      * @return {Roo.Toolbar} 
36945      */
36946     getToolbar : function(){
36947         return this.toolbar;
36948     },
36949     
36950     setActiveState : function(active)
36951     {
36952         this.active = active;
36953         this.setActiveClass(active);
36954         if(!active){
36955             if(this.fireEvent("deactivate", this) === false){
36956                 return false;
36957             }
36958             return true;
36959         }
36960         this.fireEvent("activate", this);
36961         return true;
36962     },
36963     /**
36964      * Updates this panel's element
36965      * @param {String} content The new content
36966      * @param {Boolean} loadScripts (optional) true to look for and process scripts
36967     */
36968     setContent : function(content, loadScripts){
36969         this.el.update(content, loadScripts);
36970     },
36971
36972     ignoreResize : function(w, h){
36973         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
36974             return true;
36975         }else{
36976             this.lastSize = {width: w, height: h};
36977             return false;
36978         }
36979     },
36980     /**
36981      * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
36982      * @return {Roo.UpdateManager} The UpdateManager
36983      */
36984     getUpdateManager : function(){
36985         return this.el.getUpdateManager();
36986     },
36987      /**
36988      * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
36989      * @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:
36990 <pre><code>
36991 panel.load({
36992     url: "your-url.php",
36993     params: {param1: "foo", param2: "bar"}, // or a URL encoded string
36994     callback: yourFunction,
36995     scope: yourObject, //(optional scope)
36996     discardUrl: false,
36997     nocache: false,
36998     text: "Loading...",
36999     timeout: 30,
37000     scripts: false
37001 });
37002 </code></pre>
37003      * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37004      * 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.
37005      * @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}
37006      * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37007      * @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.
37008      * @return {Roo.ContentPanel} this
37009      */
37010     load : function(){
37011         var um = this.el.getUpdateManager();
37012         um.update.apply(um, arguments);
37013         return this;
37014     },
37015
37016
37017     /**
37018      * 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.
37019      * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37020      * @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)
37021      * @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)
37022      * @return {Roo.UpdateManager} The UpdateManager
37023      */
37024     setUrl : function(url, params, loadOnce){
37025         if(this.refreshDelegate){
37026             this.removeListener("activate", this.refreshDelegate);
37027         }
37028         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37029         this.on("activate", this.refreshDelegate);
37030         return this.el.getUpdateManager();
37031     },
37032     
37033     _handleRefresh : function(url, params, loadOnce){
37034         if(!loadOnce || !this.loaded){
37035             var updater = this.el.getUpdateManager();
37036             updater.update(url, params, this._setLoaded.createDelegate(this));
37037         }
37038     },
37039     
37040     _setLoaded : function(){
37041         this.loaded = true;
37042     }, 
37043     
37044     /**
37045      * Returns this panel's id
37046      * @return {String} 
37047      */
37048     getId : function(){
37049         return this.el.id;
37050     },
37051     
37052     /** 
37053      * Returns this panel's element - used by regiosn to add.
37054      * @return {Roo.Element} 
37055      */
37056     getEl : function(){
37057         return this.wrapEl || this.el;
37058     },
37059     
37060    
37061     
37062     adjustForComponents : function(width, height)
37063     {
37064         //Roo.log('adjustForComponents ');
37065         if(this.resizeEl != this.el){
37066             width -= this.el.getFrameWidth('lr');
37067             height -= this.el.getFrameWidth('tb');
37068         }
37069         if(this.toolbar){
37070             var te = this.toolbar.getEl();
37071             te.setWidth(width);
37072             height -= te.getHeight();
37073         }
37074         if(this.footer){
37075             var te = this.footer.getEl();
37076             te.setWidth(width);
37077             height -= te.getHeight();
37078         }
37079         
37080         
37081         if(this.adjustments){
37082             width += this.adjustments[0];
37083             height += this.adjustments[1];
37084         }
37085         return {"width": width, "height": height};
37086     },
37087     
37088     setSize : function(width, height){
37089         if(this.fitToFrame && !this.ignoreResize(width, height)){
37090             if(this.fitContainer && this.resizeEl != this.el){
37091                 this.el.setSize(width, height);
37092             }
37093             var size = this.adjustForComponents(width, height);
37094             this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37095             this.fireEvent('resize', this, size.width, size.height);
37096         }
37097     },
37098     
37099     /**
37100      * Returns this panel's title
37101      * @return {String} 
37102      */
37103     getTitle : function(){
37104         
37105         if (typeof(this.title) != 'object') {
37106             return this.title;
37107         }
37108         
37109         var t = '';
37110         for (var k in this.title) {
37111             if (!this.title.hasOwnProperty(k)) {
37112                 continue;
37113             }
37114             
37115             if (k.indexOf('-') >= 0) {
37116                 var s = k.split('-');
37117                 for (var i = 0; i<s.length; i++) {
37118                     t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37119                 }
37120             } else {
37121                 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37122             }
37123         }
37124         return t;
37125     },
37126     
37127     /**
37128      * Set this panel's title
37129      * @param {String} title
37130      */
37131     setTitle : function(title){
37132         this.title = title;
37133         if(this.region){
37134             this.region.updatePanelTitle(this, title);
37135         }
37136     },
37137     
37138     /**
37139      * Returns true is this panel was configured to be closable
37140      * @return {Boolean} 
37141      */
37142     isClosable : function(){
37143         return this.closable;
37144     },
37145     
37146     beforeSlide : function(){
37147         this.el.clip();
37148         this.resizeEl.clip();
37149     },
37150     
37151     afterSlide : function(){
37152         this.el.unclip();
37153         this.resizeEl.unclip();
37154     },
37155     
37156     /**
37157      *   Force a content refresh from the URL specified in the {@link #setUrl} method.
37158      *   Will fail silently if the {@link #setUrl} method has not been called.
37159      *   This does not activate the panel, just updates its content.
37160      */
37161     refresh : function(){
37162         if(this.refreshDelegate){
37163            this.loaded = false;
37164            this.refreshDelegate();
37165         }
37166     },
37167     
37168     /**
37169      * Destroys this panel
37170      */
37171     destroy : function(){
37172         this.el.removeAllListeners();
37173         var tempEl = document.createElement("span");
37174         tempEl.appendChild(this.el.dom);
37175         tempEl.innerHTML = "";
37176         this.el.remove();
37177         this.el = null;
37178     },
37179     
37180     /**
37181      * form - if the content panel contains a form - this is a reference to it.
37182      * @type {Roo.form.Form}
37183      */
37184     form : false,
37185     /**
37186      * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37187      *    This contains a reference to it.
37188      * @type {Roo.View}
37189      */
37190     view : false,
37191     
37192       /**
37193      * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37194      * <pre><code>
37195
37196 layout.addxtype({
37197        xtype : 'Form',
37198        items: [ .... ]
37199    }
37200 );
37201
37202 </code></pre>
37203      * @param {Object} cfg Xtype definition of item to add.
37204      */
37205     
37206     
37207     getChildContainer: function () {
37208         return this.getEl();
37209     }
37210     
37211     
37212     /*
37213         var  ret = new Roo.factory(cfg);
37214         return ret;
37215         
37216         
37217         // add form..
37218         if (cfg.xtype.match(/^Form$/)) {
37219             
37220             var el;
37221             //if (this.footer) {
37222             //    el = this.footer.container.insertSibling(false, 'before');
37223             //} else {
37224                 el = this.el.createChild();
37225             //}
37226
37227             this.form = new  Roo.form.Form(cfg);
37228             
37229             
37230             if ( this.form.allItems.length) {
37231                 this.form.render(el.dom);
37232             }
37233             return this.form;
37234         }
37235         // should only have one of theses..
37236         if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37237             // views.. should not be just added - used named prop 'view''
37238             
37239             cfg.el = this.el.appendChild(document.createElement("div"));
37240             // factory?
37241             
37242             var ret = new Roo.factory(cfg);
37243              
37244              ret.render && ret.render(false, ''); // render blank..
37245             this.view = ret;
37246             return ret;
37247         }
37248         return false;
37249     }
37250     \*/
37251 });
37252  
37253 /**
37254  * @class Roo.bootstrap.panel.Grid
37255  * @extends Roo.bootstrap.panel.Content
37256  * @constructor
37257  * Create a new GridPanel.
37258  * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37259  * @param {Object} config A the config object
37260   
37261  */
37262
37263
37264
37265 Roo.bootstrap.panel.Grid = function(config)
37266 {
37267     
37268       
37269     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37270         {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37271
37272     config.el = this.wrapper;
37273     //this.el = this.wrapper;
37274     
37275       if (config.container) {
37276         // ctor'ed from a Border/panel.grid
37277         
37278         
37279         this.wrapper.setStyle("overflow", "hidden");
37280         this.wrapper.addClass('roo-grid-container');
37281
37282     }
37283     
37284     
37285     if(config.toolbar){
37286         var tool_el = this.wrapper.createChild();    
37287         this.toolbar = Roo.factory(config.toolbar);
37288         var ti = [];
37289         if (config.toolbar.items) {
37290             ti = config.toolbar.items ;
37291             delete config.toolbar.items ;
37292         }
37293         
37294         var nitems = [];
37295         this.toolbar.render(tool_el);
37296         for(var i =0;i < ti.length;i++) {
37297           //  Roo.log(['add child', items[i]]);
37298             nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37299         }
37300         this.toolbar.items = nitems;
37301         
37302         delete config.toolbar;
37303     }
37304     
37305     Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37306     config.grid.scrollBody = true;;
37307     config.grid.monitorWindowResize = false; // turn off autosizing
37308     config.grid.autoHeight = false;
37309     config.grid.autoWidth = false;
37310     
37311     this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37312     
37313     if (config.background) {
37314         // render grid on panel activation (if panel background)
37315         this.on('activate', function(gp) {
37316             if (!gp.grid.rendered) {
37317                 gp.grid.render(this.wrapper);
37318                 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");   
37319             }
37320         });
37321             
37322     } else {
37323         this.grid.render(this.wrapper);
37324         this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");               
37325
37326     }
37327     //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37328     // ??? needed ??? config.el = this.wrapper;
37329     
37330     
37331     
37332   
37333     // xtype created footer. - not sure if will work as we normally have to render first..
37334     if (this.footer && !this.footer.el && this.footer.xtype) {
37335         
37336         var ctr = this.grid.getView().getFooterPanel(true);
37337         this.footer.dataSource = this.grid.dataSource;
37338         this.footer = Roo.factory(this.footer, Roo);
37339         this.footer.render(ctr);
37340         
37341     }
37342     
37343     
37344     
37345     
37346      
37347 };
37348
37349 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37350     getId : function(){
37351         return this.grid.id;
37352     },
37353     
37354     /**
37355      * Returns the grid for this panel
37356      * @return {Roo.bootstrap.Table} 
37357      */
37358     getGrid : function(){
37359         return this.grid;    
37360     },
37361     
37362     setSize : function(width, height){
37363         if(!this.ignoreResize(width, height)){
37364             var grid = this.grid;
37365             var size = this.adjustForComponents(width, height);
37366             var gridel = grid.getGridEl();
37367             gridel.setSize(size.width, size.height);
37368             /*
37369             var thd = grid.getGridEl().select('thead',true).first();
37370             var tbd = grid.getGridEl().select('tbody', true).first();
37371             if (tbd) {
37372                 tbd.setSize(width, height - thd.getHeight());
37373             }
37374             */
37375             grid.autoSize();
37376         }
37377     },
37378      
37379     
37380     
37381     beforeSlide : function(){
37382         this.grid.getView().scroller.clip();
37383     },
37384     
37385     afterSlide : function(){
37386         this.grid.getView().scroller.unclip();
37387     },
37388     
37389     destroy : function(){
37390         this.grid.destroy();
37391         delete this.grid;
37392         Roo.bootstrap.panel.Grid.superclass.destroy.call(this); 
37393     }
37394 });
37395
37396 /**
37397  * @class Roo.bootstrap.panel.Nest
37398  * @extends Roo.bootstrap.panel.Content
37399  * @constructor
37400  * Create a new Panel, that can contain a layout.Border.
37401  * 
37402  * 
37403  * @param {Roo.BorderLayout} layout The layout for this panel
37404  * @param {String/Object} config A string to set only the title or a config object
37405  */
37406 Roo.bootstrap.panel.Nest = function(config)
37407 {
37408     // construct with only one argument..
37409     /* FIXME - implement nicer consturctors
37410     if (layout.layout) {
37411         config = layout;
37412         layout = config.layout;
37413         delete config.layout;
37414     }
37415     if (layout.xtype && !layout.getEl) {
37416         // then layout needs constructing..
37417         layout = Roo.factory(layout, Roo);
37418     }
37419     */
37420     
37421     config.el =  config.layout.getEl();
37422     
37423     Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37424     
37425     config.layout.monitorWindowResize = false; // turn off autosizing
37426     this.layout = config.layout;
37427     this.layout.getEl().addClass("roo-layout-nested-layout");
37428     
37429     
37430     
37431     
37432 };
37433
37434 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37435
37436     setSize : function(width, height){
37437         if(!this.ignoreResize(width, height)){
37438             var size = this.adjustForComponents(width, height);
37439             var el = this.layout.getEl();
37440             if (size.height < 1) {
37441                 el.setWidth(size.width);   
37442             } else {
37443                 el.setSize(size.width, size.height);
37444             }
37445             var touch = el.dom.offsetWidth;
37446             this.layout.layout();
37447             // ie requires a double layout on the first pass
37448             if(Roo.isIE && !this.initialized){
37449                 this.initialized = true;
37450                 this.layout.layout();
37451             }
37452         }
37453     },
37454     
37455     // activate all subpanels if not currently active..
37456     
37457     setActiveState : function(active){
37458         this.active = active;
37459         this.setActiveClass(active);
37460         
37461         if(!active){
37462             this.fireEvent("deactivate", this);
37463             return;
37464         }
37465         
37466         this.fireEvent("activate", this);
37467         // not sure if this should happen before or after..
37468         if (!this.layout) {
37469             return; // should not happen..
37470         }
37471         var reg = false;
37472         for (var r in this.layout.regions) {
37473             reg = this.layout.getRegion(r);
37474             if (reg.getActivePanel()) {
37475                 //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
37476                 reg.setActivePanel(reg.getActivePanel());
37477                 continue;
37478             }
37479             if (!reg.panels.length) {
37480                 continue;
37481             }
37482             reg.showPanel(reg.getPanel(0));
37483         }
37484         
37485         
37486         
37487         
37488     },
37489     
37490     /**
37491      * Returns the nested BorderLayout for this panel
37492      * @return {Roo.BorderLayout} 
37493      */
37494     getLayout : function(){
37495         return this.layout;
37496     },
37497     
37498      /**
37499      * Adds a xtype elements to the layout of the nested panel
37500      * <pre><code>
37501
37502 panel.addxtype({
37503        xtype : 'ContentPanel',
37504        region: 'west',
37505        items: [ .... ]
37506    }
37507 );
37508
37509 panel.addxtype({
37510         xtype : 'NestedLayoutPanel',
37511         region: 'west',
37512         layout: {
37513            center: { },
37514            west: { }   
37515         },
37516         items : [ ... list of content panels or nested layout panels.. ]
37517    }
37518 );
37519 </code></pre>
37520      * @param {Object} cfg Xtype definition of item to add.
37521      */
37522     addxtype : function(cfg) {
37523         return this.layout.addxtype(cfg);
37524     
37525     }
37526 });        /*
37527  * Based on:
37528  * Ext JS Library 1.1.1
37529  * Copyright(c) 2006-2007, Ext JS, LLC.
37530  *
37531  * Originally Released Under LGPL - original licence link has changed is not relivant.
37532  *
37533  * Fork - LGPL
37534  * <script type="text/javascript">
37535  */
37536 /**
37537  * @class Roo.TabPanel
37538  * @extends Roo.util.Observable
37539  * A lightweight tab container.
37540  * <br><br>
37541  * Usage:
37542  * <pre><code>
37543 // basic tabs 1, built from existing content
37544 var tabs = new Roo.TabPanel("tabs1");
37545 tabs.addTab("script", "View Script");
37546 tabs.addTab("markup", "View Markup");
37547 tabs.activate("script");
37548
37549 // more advanced tabs, built from javascript
37550 var jtabs = new Roo.TabPanel("jtabs");
37551 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37552
37553 // set up the UpdateManager
37554 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37555 var updater = tab2.getUpdateManager();
37556 updater.setDefaultUrl("ajax1.htm");
37557 tab2.on('activate', updater.refresh, updater, true);
37558
37559 // Use setUrl for Ajax loading
37560 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37561 tab3.setUrl("ajax2.htm", null, true);
37562
37563 // Disabled tab
37564 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37565 tab4.disable();
37566
37567 jtabs.activate("jtabs-1");
37568  * </code></pre>
37569  * @constructor
37570  * Create a new TabPanel.
37571  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37572  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37573  */
37574 Roo.bootstrap.panel.Tabs = function(config){
37575     /**
37576     * The container element for this TabPanel.
37577     * @type Roo.Element
37578     */
37579     this.el = Roo.get(config.el);
37580     delete config.el;
37581     if(config){
37582         if(typeof config == "boolean"){
37583             this.tabPosition = config ? "bottom" : "top";
37584         }else{
37585             Roo.apply(this, config);
37586         }
37587     }
37588     
37589     if(this.tabPosition == "bottom"){
37590         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37591         this.el.addClass("roo-tabs-bottom");
37592     }
37593     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37594     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37595     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37596     if(Roo.isIE){
37597         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37598     }
37599     if(this.tabPosition != "bottom"){
37600         /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37601          * @type Roo.Element
37602          */
37603         this.bodyEl = Roo.get(this.createBody(this.el.dom));
37604         this.el.addClass("roo-tabs-top");
37605     }
37606     this.items = [];
37607
37608     this.bodyEl.setStyle("position", "relative");
37609
37610     this.active = null;
37611     this.activateDelegate = this.activate.createDelegate(this);
37612
37613     this.addEvents({
37614         /**
37615          * @event tabchange
37616          * Fires when the active tab changes
37617          * @param {Roo.TabPanel} this
37618          * @param {Roo.TabPanelItem} activePanel The new active tab
37619          */
37620         "tabchange": true,
37621         /**
37622          * @event beforetabchange
37623          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37624          * @param {Roo.TabPanel} this
37625          * @param {Object} e Set cancel to true on this object to cancel the tab change
37626          * @param {Roo.TabPanelItem} tab The tab being changed to
37627          */
37628         "beforetabchange" : true
37629     });
37630
37631     Roo.EventManager.onWindowResize(this.onResize, this);
37632     this.cpad = this.el.getPadding("lr");
37633     this.hiddenCount = 0;
37634
37635
37636     // toolbar on the tabbar support...
37637     if (this.toolbar) {
37638         alert("no toolbar support yet");
37639         this.toolbar  = false;
37640         /*
37641         var tcfg = this.toolbar;
37642         tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');  
37643         this.toolbar = new Roo.Toolbar(tcfg);
37644         if (Roo.isSafari) {
37645             var tbl = tcfg.container.child('table', true);
37646             tbl.setAttribute('width', '100%');
37647         }
37648         */
37649         
37650     }
37651    
37652
37653
37654     Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37655 };
37656
37657 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37658     /*
37659      *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37660      */
37661     tabPosition : "top",
37662     /*
37663      *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37664      */
37665     currentTabWidth : 0,
37666     /*
37667      *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37668      */
37669     minTabWidth : 40,
37670     /*
37671      *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37672      */
37673     maxTabWidth : 250,
37674     /*
37675      *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37676      */
37677     preferredTabWidth : 175,
37678     /*
37679      *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37680      */
37681     resizeTabs : false,
37682     /*
37683      *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37684      */
37685     monitorResize : true,
37686     /*
37687      *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar. 
37688      */
37689     toolbar : false,
37690
37691     /**
37692      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37693      * @param {String} id The id of the div to use <b>or create</b>
37694      * @param {String} text The text for the tab
37695      * @param {String} content (optional) Content to put in the TabPanelItem body
37696      * @param {Boolean} closable (optional) True to create a close icon on the tab
37697      * @return {Roo.TabPanelItem} The created TabPanelItem
37698      */
37699     addTab : function(id, text, content, closable, tpl)
37700     {
37701         var item = new Roo.bootstrap.panel.TabItem({
37702             panel: this,
37703             id : id,
37704             text : text,
37705             closable : closable,
37706             tpl : tpl
37707         });
37708         this.addTabItem(item);
37709         if(content){
37710             item.setContent(content);
37711         }
37712         return item;
37713     },
37714
37715     /**
37716      * Returns the {@link Roo.TabPanelItem} with the specified id/index
37717      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37718      * @return {Roo.TabPanelItem}
37719      */
37720     getTab : function(id){
37721         return this.items[id];
37722     },
37723
37724     /**
37725      * Hides the {@link Roo.TabPanelItem} with the specified id/index
37726      * @param {String/Number} id The id or index of the TabPanelItem to hide.
37727      */
37728     hideTab : function(id){
37729         var t = this.items[id];
37730         if(!t.isHidden()){
37731            t.setHidden(true);
37732            this.hiddenCount++;
37733            this.autoSizeTabs();
37734         }
37735     },
37736
37737     /**
37738      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
37739      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
37740      */
37741     unhideTab : function(id){
37742         var t = this.items[id];
37743         if(t.isHidden()){
37744            t.setHidden(false);
37745            this.hiddenCount--;
37746            this.autoSizeTabs();
37747         }
37748     },
37749
37750     /**
37751      * Adds an existing {@link Roo.TabPanelItem}.
37752      * @param {Roo.TabPanelItem} item The TabPanelItem to add
37753      */
37754     addTabItem : function(item){
37755         this.items[item.id] = item;
37756         this.items.push(item);
37757       //  if(this.resizeTabs){
37758     //       item.setWidth(this.currentTabWidth || this.preferredTabWidth);
37759   //         this.autoSizeTabs();
37760 //        }else{
37761 //            item.autoSize();
37762        // }
37763     },
37764
37765     /**
37766      * Removes a {@link Roo.TabPanelItem}.
37767      * @param {String/Number} id The id or index of the TabPanelItem to remove.
37768      */
37769     removeTab : function(id){
37770         var items = this.items;
37771         var tab = items[id];
37772         if(!tab) { return; }
37773         var index = items.indexOf(tab);
37774         if(this.active == tab && items.length > 1){
37775             var newTab = this.getNextAvailable(index);
37776             if(newTab) {
37777                 newTab.activate();
37778             }
37779         }
37780         this.stripEl.dom.removeChild(tab.pnode.dom);
37781         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
37782             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
37783         }
37784         items.splice(index, 1);
37785         delete this.items[tab.id];
37786         tab.fireEvent("close", tab);
37787         tab.purgeListeners();
37788         this.autoSizeTabs();
37789     },
37790
37791     getNextAvailable : function(start){
37792         var items = this.items;
37793         var index = start;
37794         // look for a next tab that will slide over to
37795         // replace the one being removed
37796         while(index < items.length){
37797             var item = items[++index];
37798             if(item && !item.isHidden()){
37799                 return item;
37800             }
37801         }
37802         // if one isn't found select the previous tab (on the left)
37803         index = start;
37804         while(index >= 0){
37805             var item = items[--index];
37806             if(item && !item.isHidden()){
37807                 return item;
37808             }
37809         }
37810         return null;
37811     },
37812
37813     /**
37814      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
37815      * @param {String/Number} id The id or index of the TabPanelItem to disable.
37816      */
37817     disableTab : function(id){
37818         var tab = this.items[id];
37819         if(tab && this.active != tab){
37820             tab.disable();
37821         }
37822     },
37823
37824     /**
37825      * Enables a {@link Roo.TabPanelItem} that is disabled.
37826      * @param {String/Number} id The id or index of the TabPanelItem to enable.
37827      */
37828     enableTab : function(id){
37829         var tab = this.items[id];
37830         tab.enable();
37831     },
37832
37833     /**
37834      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
37835      * @param {String/Number} id The id or index of the TabPanelItem to activate.
37836      * @return {Roo.TabPanelItem} The TabPanelItem.
37837      */
37838     activate : function(id){
37839         var tab = this.items[id];
37840         if(!tab){
37841             return null;
37842         }
37843         if(tab == this.active || tab.disabled){
37844             return tab;
37845         }
37846         var e = {};
37847         this.fireEvent("beforetabchange", this, e, tab);
37848         if(e.cancel !== true && !tab.disabled){
37849             if(this.active){
37850                 this.active.hide();
37851             }
37852             this.active = this.items[id];
37853             this.active.show();
37854             this.fireEvent("tabchange", this, this.active);
37855         }
37856         return tab;
37857     },
37858
37859     /**
37860      * Gets the active {@link Roo.TabPanelItem}.
37861      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
37862      */
37863     getActiveTab : function(){
37864         return this.active;
37865     },
37866
37867     /**
37868      * Updates the tab body element to fit the height of the container element
37869      * for overflow scrolling
37870      * @param {Number} targetHeight (optional) Override the starting height from the elements height
37871      */
37872     syncHeight : function(targetHeight){
37873         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37874         var bm = this.bodyEl.getMargins();
37875         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
37876         this.bodyEl.setHeight(newHeight);
37877         return newHeight;
37878     },
37879
37880     onResize : function(){
37881         if(this.monitorResize){
37882             this.autoSizeTabs();
37883         }
37884     },
37885
37886     /**
37887      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
37888      */
37889     beginUpdate : function(){
37890         this.updating = true;
37891     },
37892
37893     /**
37894      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
37895      */
37896     endUpdate : function(){
37897         this.updating = false;
37898         this.autoSizeTabs();
37899     },
37900
37901     /**
37902      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
37903      */
37904     autoSizeTabs : function(){
37905         var count = this.items.length;
37906         var vcount = count - this.hiddenCount;
37907         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
37908             return;
37909         }
37910         var w = Math.max(this.el.getWidth() - this.cpad, 10);
37911         var availWidth = Math.floor(w / vcount);
37912         var b = this.stripBody;
37913         if(b.getWidth() > w){
37914             var tabs = this.items;
37915             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
37916             if(availWidth < this.minTabWidth){
37917                 /*if(!this.sleft){    // incomplete scrolling code
37918                     this.createScrollButtons();
37919                 }
37920                 this.showScroll();
37921                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
37922             }
37923         }else{
37924             if(this.currentTabWidth < this.preferredTabWidth){
37925                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
37926             }
37927         }
37928     },
37929
37930     /**
37931      * Returns the number of tabs in this TabPanel.
37932      * @return {Number}
37933      */
37934      getCount : function(){
37935          return this.items.length;
37936      },
37937
37938     /**
37939      * Resizes all the tabs to the passed width
37940      * @param {Number} The new width
37941      */
37942     setTabWidth : function(width){
37943         this.currentTabWidth = width;
37944         for(var i = 0, len = this.items.length; i < len; i++) {
37945                 if(!this.items[i].isHidden()) {
37946                 this.items[i].setWidth(width);
37947             }
37948         }
37949     },
37950
37951     /**
37952      * Destroys this TabPanel
37953      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
37954      */
37955     destroy : function(removeEl){
37956         Roo.EventManager.removeResizeListener(this.onResize, this);
37957         for(var i = 0, len = this.items.length; i < len; i++){
37958             this.items[i].purgeListeners();
37959         }
37960         if(removeEl === true){
37961             this.el.update("");
37962             this.el.remove();
37963         }
37964     },
37965     
37966     createStrip : function(container)
37967     {
37968         var strip = document.createElement("nav");
37969         strip.className = "navbar navbar-default"; //"x-tabs-wrap";
37970         container.appendChild(strip);
37971         return strip;
37972     },
37973     
37974     createStripList : function(strip)
37975     {
37976         // div wrapper for retard IE
37977         // returns the "tr" element.
37978         strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
37979         //'<div class="x-tabs-strip-wrap">'+
37980           //  '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
37981           //  '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
37982         return strip.firstChild; //.firstChild.firstChild.firstChild;
37983     },
37984     createBody : function(container)
37985     {
37986         var body = document.createElement("div");
37987         Roo.id(body, "tab-body");
37988         //Roo.fly(body).addClass("x-tabs-body");
37989         Roo.fly(body).addClass("tab-content");
37990         container.appendChild(body);
37991         return body;
37992     },
37993     createItemBody :function(bodyEl, id){
37994         var body = Roo.getDom(id);
37995         if(!body){
37996             body = document.createElement("div");
37997             body.id = id;
37998         }
37999         //Roo.fly(body).addClass("x-tabs-item-body");
38000         Roo.fly(body).addClass("tab-pane");
38001          bodyEl.insertBefore(body, bodyEl.firstChild);
38002         return body;
38003     },
38004     /** @private */
38005     createStripElements :  function(stripEl, text, closable, tpl)
38006     {
38007         var td = document.createElement("li"); // was td..
38008         
38009         
38010         //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38011         
38012         
38013         stripEl.appendChild(td);
38014         /*if(closable){
38015             td.className = "x-tabs-closable";
38016             if(!this.closeTpl){
38017                 this.closeTpl = new Roo.Template(
38018                    '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38019                    '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38020                    '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
38021                 );
38022             }
38023             var el = this.closeTpl.overwrite(td, {"text": text});
38024             var close = el.getElementsByTagName("div")[0];
38025             var inner = el.getElementsByTagName("em")[0];
38026             return {"el": el, "close": close, "inner": inner};
38027         } else {
38028         */
38029         // not sure what this is..
38030 //            if(!this.tabTpl){
38031                 //this.tabTpl = new Roo.Template(
38032                 //   '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38033                 //   '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38034                 //);
38035 //                this.tabTpl = new Roo.Template(
38036 //                   '<a href="#">' +
38037 //                   '<span unselectable="on"' +
38038 //                            (this.disableTooltips ? '' : ' title="{text}"') +
38039 //                            ' >{text}</span></a>'
38040 //                );
38041 //                
38042 //            }
38043
38044
38045             var template = tpl || this.tabTpl || false;
38046             
38047             if(!template){
38048                 
38049                 template = new Roo.Template(
38050                    '<a href="#">' +
38051                    '<span unselectable="on"' +
38052                             (this.disableTooltips ? '' : ' title="{text}"') +
38053                             ' >{text}</span></a>'
38054                 );
38055             }
38056             
38057             switch (typeof(template)) {
38058                 case 'object' :
38059                     break;
38060                 case 'string' :
38061                     template = new Roo.Template(template);
38062                     break;
38063                 default :
38064                     break;
38065             }
38066             
38067             var el = template.overwrite(td, {"text": text});
38068             
38069             var inner = el.getElementsByTagName("span")[0];
38070             
38071             return {"el": el, "inner": inner};
38072             
38073     }
38074         
38075     
38076 });
38077
38078 /**
38079  * @class Roo.TabPanelItem
38080  * @extends Roo.util.Observable
38081  * Represents an individual item (tab plus body) in a TabPanel.
38082  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38083  * @param {String} id The id of this TabPanelItem
38084  * @param {String} text The text for the tab of this TabPanelItem
38085  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38086  */
38087 Roo.bootstrap.panel.TabItem = function(config){
38088     /**
38089      * The {@link Roo.TabPanel} this TabPanelItem belongs to
38090      * @type Roo.TabPanel
38091      */
38092     this.tabPanel = config.panel;
38093     /**
38094      * The id for this TabPanelItem
38095      * @type String
38096      */
38097     this.id = config.id;
38098     /** @private */
38099     this.disabled = false;
38100     /** @private */
38101     this.text = config.text;
38102     /** @private */
38103     this.loaded = false;
38104     this.closable = config.closable;
38105
38106     /**
38107      * The body element for this TabPanelItem.
38108      * @type Roo.Element
38109      */
38110     this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38111     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38112     this.bodyEl.setStyle("display", "block");
38113     this.bodyEl.setStyle("zoom", "1");
38114     //this.hideAction();
38115
38116     var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38117     /** @private */
38118     this.el = Roo.get(els.el);
38119     this.inner = Roo.get(els.inner, true);
38120     this.textEl = Roo.get(this.el.dom.firstChild, true);
38121     this.pnode = Roo.get(els.el.parentNode, true);
38122 //    this.el.on("mousedown", this.onTabMouseDown, this);
38123     this.el.on("click", this.onTabClick, this);
38124     /** @private */
38125     if(config.closable){
38126         var c = Roo.get(els.close, true);
38127         c.dom.title = this.closeText;
38128         c.addClassOnOver("close-over");
38129         c.on("click", this.closeClick, this);
38130      }
38131
38132     this.addEvents({
38133          /**
38134          * @event activate
38135          * Fires when this tab becomes the active tab.
38136          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38137          * @param {Roo.TabPanelItem} this
38138          */
38139         "activate": true,
38140         /**
38141          * @event beforeclose
38142          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38143          * @param {Roo.TabPanelItem} this
38144          * @param {Object} e Set cancel to true on this object to cancel the close.
38145          */
38146         "beforeclose": true,
38147         /**
38148          * @event close
38149          * Fires when this tab is closed.
38150          * @param {Roo.TabPanelItem} this
38151          */
38152          "close": true,
38153         /**
38154          * @event deactivate
38155          * Fires when this tab is no longer the active tab.
38156          * @param {Roo.TabPanel} tabPanel The parent TabPanel
38157          * @param {Roo.TabPanelItem} this
38158          */
38159          "deactivate" : true
38160     });
38161     this.hidden = false;
38162
38163     Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38164 };
38165
38166 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38167            {
38168     purgeListeners : function(){
38169        Roo.util.Observable.prototype.purgeListeners.call(this);
38170        this.el.removeAllListeners();
38171     },
38172     /**
38173      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38174      */
38175     show : function(){
38176         this.pnode.addClass("active");
38177         this.showAction();
38178         if(Roo.isOpera){
38179             this.tabPanel.stripWrap.repaint();
38180         }
38181         this.fireEvent("activate", this.tabPanel, this);
38182     },
38183
38184     /**
38185      * Returns true if this tab is the active tab.
38186      * @return {Boolean}
38187      */
38188     isActive : function(){
38189         return this.tabPanel.getActiveTab() == this;
38190     },
38191
38192     /**
38193      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38194      */
38195     hide : function(){
38196         this.pnode.removeClass("active");
38197         this.hideAction();
38198         this.fireEvent("deactivate", this.tabPanel, this);
38199     },
38200
38201     hideAction : function(){
38202         this.bodyEl.hide();
38203         this.bodyEl.setStyle("position", "absolute");
38204         this.bodyEl.setLeft("-20000px");
38205         this.bodyEl.setTop("-20000px");
38206     },
38207
38208     showAction : function(){
38209         this.bodyEl.setStyle("position", "relative");
38210         this.bodyEl.setTop("");
38211         this.bodyEl.setLeft("");
38212         this.bodyEl.show();
38213     },
38214
38215     /**
38216      * Set the tooltip for the tab.
38217      * @param {String} tooltip The tab's tooltip
38218      */
38219     setTooltip : function(text){
38220         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38221             this.textEl.dom.qtip = text;
38222             this.textEl.dom.removeAttribute('title');
38223         }else{
38224             this.textEl.dom.title = text;
38225         }
38226     },
38227
38228     onTabClick : function(e){
38229         e.preventDefault();
38230         this.tabPanel.activate(this.id);
38231     },
38232
38233     onTabMouseDown : function(e){
38234         e.preventDefault();
38235         this.tabPanel.activate(this.id);
38236     },
38237 /*
38238     getWidth : function(){
38239         return this.inner.getWidth();
38240     },
38241
38242     setWidth : function(width){
38243         var iwidth = width - this.pnode.getPadding("lr");
38244         this.inner.setWidth(iwidth);
38245         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38246         this.pnode.setWidth(width);
38247     },
38248 */
38249     /**
38250      * Show or hide the tab
38251      * @param {Boolean} hidden True to hide or false to show.
38252      */
38253     setHidden : function(hidden){
38254         this.hidden = hidden;
38255         this.pnode.setStyle("display", hidden ? "none" : "");
38256     },
38257
38258     /**
38259      * Returns true if this tab is "hidden"
38260      * @return {Boolean}
38261      */
38262     isHidden : function(){
38263         return this.hidden;
38264     },
38265
38266     /**
38267      * Returns the text for this tab
38268      * @return {String}
38269      */
38270     getText : function(){
38271         return this.text;
38272     },
38273     /*
38274     autoSize : function(){
38275         //this.el.beginMeasure();
38276         this.textEl.setWidth(1);
38277         /*
38278          *  #2804 [new] Tabs in Roojs
38279          *  increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38280          */
38281         //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38282         //this.el.endMeasure();
38283     //},
38284
38285     /**
38286      * Sets the text for the tab (Note: this also sets the tooltip text)
38287      * @param {String} text The tab's text and tooltip
38288      */
38289     setText : function(text){
38290         this.text = text;
38291         this.textEl.update(text);
38292         this.setTooltip(text);
38293         //if(!this.tabPanel.resizeTabs){
38294         //    this.autoSize();
38295         //}
38296     },
38297     /**
38298      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38299      */
38300     activate : function(){
38301         this.tabPanel.activate(this.id);
38302     },
38303
38304     /**
38305      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38306      */
38307     disable : function(){
38308         if(this.tabPanel.active != this){
38309             this.disabled = true;
38310             this.pnode.addClass("disabled");
38311         }
38312     },
38313
38314     /**
38315      * Enables this TabPanelItem if it was previously disabled.
38316      */
38317     enable : function(){
38318         this.disabled = false;
38319         this.pnode.removeClass("disabled");
38320     },
38321
38322     /**
38323      * Sets the content for this TabPanelItem.
38324      * @param {String} content The content
38325      * @param {Boolean} loadScripts true to look for and load scripts
38326      */
38327     setContent : function(content, loadScripts){
38328         this.bodyEl.update(content, loadScripts);
38329     },
38330
38331     /**
38332      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38333      * @return {Roo.UpdateManager} The UpdateManager
38334      */
38335     getUpdateManager : function(){
38336         return this.bodyEl.getUpdateManager();
38337     },
38338
38339     /**
38340      * Set a URL to be used to load the content for this TabPanelItem.
38341      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38342      * @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)
38343      * @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)
38344      * @return {Roo.UpdateManager} The UpdateManager
38345      */
38346     setUrl : function(url, params, loadOnce){
38347         if(this.refreshDelegate){
38348             this.un('activate', this.refreshDelegate);
38349         }
38350         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38351         this.on("activate", this.refreshDelegate);
38352         return this.bodyEl.getUpdateManager();
38353     },
38354
38355     /** @private */
38356     _handleRefresh : function(url, params, loadOnce){
38357         if(!loadOnce || !this.loaded){
38358             var updater = this.bodyEl.getUpdateManager();
38359             updater.update(url, params, this._setLoaded.createDelegate(this));
38360         }
38361     },
38362
38363     /**
38364      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
38365      *   Will fail silently if the setUrl method has not been called.
38366      *   This does not activate the panel, just updates its content.
38367      */
38368     refresh : function(){
38369         if(this.refreshDelegate){
38370            this.loaded = false;
38371            this.refreshDelegate();
38372         }
38373     },
38374
38375     /** @private */
38376     _setLoaded : function(){
38377         this.loaded = true;
38378     },
38379
38380     /** @private */
38381     closeClick : function(e){
38382         var o = {};
38383         e.stopEvent();
38384         this.fireEvent("beforeclose", this, o);
38385         if(o.cancel !== true){
38386             this.tabPanel.removeTab(this.id);
38387         }
38388     },
38389     /**
38390      * The text displayed in the tooltip for the close icon.
38391      * @type String
38392      */
38393     closeText : "Close this tab"
38394 });
38395 /**
38396 *    This script refer to:
38397 *    Title: International Telephone Input
38398 *    Author: Jack O'Connor
38399 *    Code version:  v12.1.12
38400 *    Availability: https://github.com/jackocnr/intl-tel-input.git
38401 **/
38402
38403 Roo.bootstrap.PhoneInputData = function() {
38404     var d = [
38405       [
38406         "Afghanistan (‫افغانستان‬‎)",
38407         "af",
38408         "93"
38409       ],
38410       [
38411         "Albania (Shqipëri)",
38412         "al",
38413         "355"
38414       ],
38415       [
38416         "Algeria (‫الجزائر‬‎)",
38417         "dz",
38418         "213"
38419       ],
38420       [
38421         "American Samoa",
38422         "as",
38423         "1684"
38424       ],
38425       [
38426         "Andorra",
38427         "ad",
38428         "376"
38429       ],
38430       [
38431         "Angola",
38432         "ao",
38433         "244"
38434       ],
38435       [
38436         "Anguilla",
38437         "ai",
38438         "1264"
38439       ],
38440       [
38441         "Antigua and Barbuda",
38442         "ag",
38443         "1268"
38444       ],
38445       [
38446         "Argentina",
38447         "ar",
38448         "54"
38449       ],
38450       [
38451         "Armenia (Հայաստան)",
38452         "am",
38453         "374"
38454       ],
38455       [
38456         "Aruba",
38457         "aw",
38458         "297"
38459       ],
38460       [
38461         "Australia",
38462         "au",
38463         "61",
38464         0
38465       ],
38466       [
38467         "Austria (Österreich)",
38468         "at",
38469         "43"
38470       ],
38471       [
38472         "Azerbaijan (Azərbaycan)",
38473         "az",
38474         "994"
38475       ],
38476       [
38477         "Bahamas",
38478         "bs",
38479         "1242"
38480       ],
38481       [
38482         "Bahrain (‫البحرين‬‎)",
38483         "bh",
38484         "973"
38485       ],
38486       [
38487         "Bangladesh (বাংলাদেশ)",
38488         "bd",
38489         "880"
38490       ],
38491       [
38492         "Barbados",
38493         "bb",
38494         "1246"
38495       ],
38496       [
38497         "Belarus (Беларусь)",
38498         "by",
38499         "375"
38500       ],
38501       [
38502         "Belgium (België)",
38503         "be",
38504         "32"
38505       ],
38506       [
38507         "Belize",
38508         "bz",
38509         "501"
38510       ],
38511       [
38512         "Benin (Bénin)",
38513         "bj",
38514         "229"
38515       ],
38516       [
38517         "Bermuda",
38518         "bm",
38519         "1441"
38520       ],
38521       [
38522         "Bhutan (འབྲུག)",
38523         "bt",
38524         "975"
38525       ],
38526       [
38527         "Bolivia",
38528         "bo",
38529         "591"
38530       ],
38531       [
38532         "Bosnia and Herzegovina (Босна и Херцеговина)",
38533         "ba",
38534         "387"
38535       ],
38536       [
38537         "Botswana",
38538         "bw",
38539         "267"
38540       ],
38541       [
38542         "Brazil (Brasil)",
38543         "br",
38544         "55"
38545       ],
38546       [
38547         "British Indian Ocean Territory",
38548         "io",
38549         "246"
38550       ],
38551       [
38552         "British Virgin Islands",
38553         "vg",
38554         "1284"
38555       ],
38556       [
38557         "Brunei",
38558         "bn",
38559         "673"
38560       ],
38561       [
38562         "Bulgaria (България)",
38563         "bg",
38564         "359"
38565       ],
38566       [
38567         "Burkina Faso",
38568         "bf",
38569         "226"
38570       ],
38571       [
38572         "Burundi (Uburundi)",
38573         "bi",
38574         "257"
38575       ],
38576       [
38577         "Cambodia (កម្ពុជា)",
38578         "kh",
38579         "855"
38580       ],
38581       [
38582         "Cameroon (Cameroun)",
38583         "cm",
38584         "237"
38585       ],
38586       [
38587         "Canada",
38588         "ca",
38589         "1",
38590         1,
38591         ["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"]
38592       ],
38593       [
38594         "Cape Verde (Kabu Verdi)",
38595         "cv",
38596         "238"
38597       ],
38598       [
38599         "Caribbean Netherlands",
38600         "bq",
38601         "599",
38602         1
38603       ],
38604       [
38605         "Cayman Islands",
38606         "ky",
38607         "1345"
38608       ],
38609       [
38610         "Central African Republic (République centrafricaine)",
38611         "cf",
38612         "236"
38613       ],
38614       [
38615         "Chad (Tchad)",
38616         "td",
38617         "235"
38618       ],
38619       [
38620         "Chile",
38621         "cl",
38622         "56"
38623       ],
38624       [
38625         "China (中国)",
38626         "cn",
38627         "86"
38628       ],
38629       [
38630         "Christmas Island",
38631         "cx",
38632         "61",
38633         2
38634       ],
38635       [
38636         "Cocos (Keeling) Islands",
38637         "cc",
38638         "61",
38639         1
38640       ],
38641       [
38642         "Colombia",
38643         "co",
38644         "57"
38645       ],
38646       [
38647         "Comoros (‫جزر القمر‬‎)",
38648         "km",
38649         "269"
38650       ],
38651       [
38652         "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38653         "cd",
38654         "243"
38655       ],
38656       [
38657         "Congo (Republic) (Congo-Brazzaville)",
38658         "cg",
38659         "242"
38660       ],
38661       [
38662         "Cook Islands",
38663         "ck",
38664         "682"
38665       ],
38666       [
38667         "Costa Rica",
38668         "cr",
38669         "506"
38670       ],
38671       [
38672         "Côte d’Ivoire",
38673         "ci",
38674         "225"
38675       ],
38676       [
38677         "Croatia (Hrvatska)",
38678         "hr",
38679         "385"
38680       ],
38681       [
38682         "Cuba",
38683         "cu",
38684         "53"
38685       ],
38686       [
38687         "Curaçao",
38688         "cw",
38689         "599",
38690         0
38691       ],
38692       [
38693         "Cyprus (Κύπρος)",
38694         "cy",
38695         "357"
38696       ],
38697       [
38698         "Czech Republic (Česká republika)",
38699         "cz",
38700         "420"
38701       ],
38702       [
38703         "Denmark (Danmark)",
38704         "dk",
38705         "45"
38706       ],
38707       [
38708         "Djibouti",
38709         "dj",
38710         "253"
38711       ],
38712       [
38713         "Dominica",
38714         "dm",
38715         "1767"
38716       ],
38717       [
38718         "Dominican Republic (República Dominicana)",
38719         "do",
38720         "1",
38721         2,
38722         ["809", "829", "849"]
38723       ],
38724       [
38725         "Ecuador",
38726         "ec",
38727         "593"
38728       ],
38729       [
38730         "Egypt (‫مصر‬‎)",
38731         "eg",
38732         "20"
38733       ],
38734       [
38735         "El Salvador",
38736         "sv",
38737         "503"
38738       ],
38739       [
38740         "Equatorial Guinea (Guinea Ecuatorial)",
38741         "gq",
38742         "240"
38743       ],
38744       [
38745         "Eritrea",
38746         "er",
38747         "291"
38748       ],
38749       [
38750         "Estonia (Eesti)",
38751         "ee",
38752         "372"
38753       ],
38754       [
38755         "Ethiopia",
38756         "et",
38757         "251"
38758       ],
38759       [
38760         "Falkland Islands (Islas Malvinas)",
38761         "fk",
38762         "500"
38763       ],
38764       [
38765         "Faroe Islands (Føroyar)",
38766         "fo",
38767         "298"
38768       ],
38769       [
38770         "Fiji",
38771         "fj",
38772         "679"
38773       ],
38774       [
38775         "Finland (Suomi)",
38776         "fi",
38777         "358",
38778         0
38779       ],
38780       [
38781         "France",
38782         "fr",
38783         "33"
38784       ],
38785       [
38786         "French Guiana (Guyane française)",
38787         "gf",
38788         "594"
38789       ],
38790       [
38791         "French Polynesia (Polynésie française)",
38792         "pf",
38793         "689"
38794       ],
38795       [
38796         "Gabon",
38797         "ga",
38798         "241"
38799       ],
38800       [
38801         "Gambia",
38802         "gm",
38803         "220"
38804       ],
38805       [
38806         "Georgia (საქართველო)",
38807         "ge",
38808         "995"
38809       ],
38810       [
38811         "Germany (Deutschland)",
38812         "de",
38813         "49"
38814       ],
38815       [
38816         "Ghana (Gaana)",
38817         "gh",
38818         "233"
38819       ],
38820       [
38821         "Gibraltar",
38822         "gi",
38823         "350"
38824       ],
38825       [
38826         "Greece (Ελλάδα)",
38827         "gr",
38828         "30"
38829       ],
38830       [
38831         "Greenland (Kalaallit Nunaat)",
38832         "gl",
38833         "299"
38834       ],
38835       [
38836         "Grenada",
38837         "gd",
38838         "1473"
38839       ],
38840       [
38841         "Guadeloupe",
38842         "gp",
38843         "590",
38844         0
38845       ],
38846       [
38847         "Guam",
38848         "gu",
38849         "1671"
38850       ],
38851       [
38852         "Guatemala",
38853         "gt",
38854         "502"
38855       ],
38856       [
38857         "Guernsey",
38858         "gg",
38859         "44",
38860         1
38861       ],
38862       [
38863         "Guinea (Guinée)",
38864         "gn",
38865         "224"
38866       ],
38867       [
38868         "Guinea-Bissau (Guiné Bissau)",
38869         "gw",
38870         "245"
38871       ],
38872       [
38873         "Guyana",
38874         "gy",
38875         "592"
38876       ],
38877       [
38878         "Haiti",
38879         "ht",
38880         "509"
38881       ],
38882       [
38883         "Honduras",
38884         "hn",
38885         "504"
38886       ],
38887       [
38888         "Hong Kong (香港)",
38889         "hk",
38890         "852"
38891       ],
38892       [
38893         "Hungary (Magyarország)",
38894         "hu",
38895         "36"
38896       ],
38897       [
38898         "Iceland (Ísland)",
38899         "is",
38900         "354"
38901       ],
38902       [
38903         "India (भारत)",
38904         "in",
38905         "91"
38906       ],
38907       [
38908         "Indonesia",
38909         "id",
38910         "62"
38911       ],
38912       [
38913         "Iran (‫ایران‬‎)",
38914         "ir",
38915         "98"
38916       ],
38917       [
38918         "Iraq (‫العراق‬‎)",
38919         "iq",
38920         "964"
38921       ],
38922       [
38923         "Ireland",
38924         "ie",
38925         "353"
38926       ],
38927       [
38928         "Isle of Man",
38929         "im",
38930         "44",
38931         2
38932       ],
38933       [
38934         "Israel (‫ישראל‬‎)",
38935         "il",
38936         "972"
38937       ],
38938       [
38939         "Italy (Italia)",
38940         "it",
38941         "39",
38942         0
38943       ],
38944       [
38945         "Jamaica",
38946         "jm",
38947         "1876"
38948       ],
38949       [
38950         "Japan (日本)",
38951         "jp",
38952         "81"
38953       ],
38954       [
38955         "Jersey",
38956         "je",
38957         "44",
38958         3
38959       ],
38960       [
38961         "Jordan (‫الأردن‬‎)",
38962         "jo",
38963         "962"
38964       ],
38965       [
38966         "Kazakhstan (Казахстан)",
38967         "kz",
38968         "7",
38969         1
38970       ],
38971       [
38972         "Kenya",
38973         "ke",
38974         "254"
38975       ],
38976       [
38977         "Kiribati",
38978         "ki",
38979         "686"
38980       ],
38981       [
38982         "Kosovo",
38983         "xk",
38984         "383"
38985       ],
38986       [
38987         "Kuwait (‫الكويت‬‎)",
38988         "kw",
38989         "965"
38990       ],
38991       [
38992         "Kyrgyzstan (Кыргызстан)",
38993         "kg",
38994         "996"
38995       ],
38996       [
38997         "Laos (ລາວ)",
38998         "la",
38999         "856"
39000       ],
39001       [
39002         "Latvia (Latvija)",
39003         "lv",
39004         "371"
39005       ],
39006       [
39007         "Lebanon (‫لبنان‬‎)",
39008         "lb",
39009         "961"
39010       ],
39011       [
39012         "Lesotho",
39013         "ls",
39014         "266"
39015       ],
39016       [
39017         "Liberia",
39018         "lr",
39019         "231"
39020       ],
39021       [
39022         "Libya (‫ليبيا‬‎)",
39023         "ly",
39024         "218"
39025       ],
39026       [
39027         "Liechtenstein",
39028         "li",
39029         "423"
39030       ],
39031       [
39032         "Lithuania (Lietuva)",
39033         "lt",
39034         "370"
39035       ],
39036       [
39037         "Luxembourg",
39038         "lu",
39039         "352"
39040       ],
39041       [
39042         "Macau (澳門)",
39043         "mo",
39044         "853"
39045       ],
39046       [
39047         "Macedonia (FYROM) (Македонија)",
39048         "mk",
39049         "389"
39050       ],
39051       [
39052         "Madagascar (Madagasikara)",
39053         "mg",
39054         "261"
39055       ],
39056       [
39057         "Malawi",
39058         "mw",
39059         "265"
39060       ],
39061       [
39062         "Malaysia",
39063         "my",
39064         "60"
39065       ],
39066       [
39067         "Maldives",
39068         "mv",
39069         "960"
39070       ],
39071       [
39072         "Mali",
39073         "ml",
39074         "223"
39075       ],
39076       [
39077         "Malta",
39078         "mt",
39079         "356"
39080       ],
39081       [
39082         "Marshall Islands",
39083         "mh",
39084         "692"
39085       ],
39086       [
39087         "Martinique",
39088         "mq",
39089         "596"
39090       ],
39091       [
39092         "Mauritania (‫موريتانيا‬‎)",
39093         "mr",
39094         "222"
39095       ],
39096       [
39097         "Mauritius (Moris)",
39098         "mu",
39099         "230"
39100       ],
39101       [
39102         "Mayotte",
39103         "yt",
39104         "262",
39105         1
39106       ],
39107       [
39108         "Mexico (México)",
39109         "mx",
39110         "52"
39111       ],
39112       [
39113         "Micronesia",
39114         "fm",
39115         "691"
39116       ],
39117       [
39118         "Moldova (Republica Moldova)",
39119         "md",
39120         "373"
39121       ],
39122       [
39123         "Monaco",
39124         "mc",
39125         "377"
39126       ],
39127       [
39128         "Mongolia (Монгол)",
39129         "mn",
39130         "976"
39131       ],
39132       [
39133         "Montenegro (Crna Gora)",
39134         "me",
39135         "382"
39136       ],
39137       [
39138         "Montserrat",
39139         "ms",
39140         "1664"
39141       ],
39142       [
39143         "Morocco (‫المغرب‬‎)",
39144         "ma",
39145         "212",
39146         0
39147       ],
39148       [
39149         "Mozambique (Moçambique)",
39150         "mz",
39151         "258"
39152       ],
39153       [
39154         "Myanmar (Burma) (မြန်မာ)",
39155         "mm",
39156         "95"
39157       ],
39158       [
39159         "Namibia (Namibië)",
39160         "na",
39161         "264"
39162       ],
39163       [
39164         "Nauru",
39165         "nr",
39166         "674"
39167       ],
39168       [
39169         "Nepal (नेपाल)",
39170         "np",
39171         "977"
39172       ],
39173       [
39174         "Netherlands (Nederland)",
39175         "nl",
39176         "31"
39177       ],
39178       [
39179         "New Caledonia (Nouvelle-Calédonie)",
39180         "nc",
39181         "687"
39182       ],
39183       [
39184         "New Zealand",
39185         "nz",
39186         "64"
39187       ],
39188       [
39189         "Nicaragua",
39190         "ni",
39191         "505"
39192       ],
39193       [
39194         "Niger (Nijar)",
39195         "ne",
39196         "227"
39197       ],
39198       [
39199         "Nigeria",
39200         "ng",
39201         "234"
39202       ],
39203       [
39204         "Niue",
39205         "nu",
39206         "683"
39207       ],
39208       [
39209         "Norfolk Island",
39210         "nf",
39211         "672"
39212       ],
39213       [
39214         "North Korea (조선 민주주의 인민 공화국)",
39215         "kp",
39216         "850"
39217       ],
39218       [
39219         "Northern Mariana Islands",
39220         "mp",
39221         "1670"
39222       ],
39223       [
39224         "Norway (Norge)",
39225         "no",
39226         "47",
39227         0
39228       ],
39229       [
39230         "Oman (‫عُمان‬‎)",
39231         "om",
39232         "968"
39233       ],
39234       [
39235         "Pakistan (‫پاکستان‬‎)",
39236         "pk",
39237         "92"
39238       ],
39239       [
39240         "Palau",
39241         "pw",
39242         "680"
39243       ],
39244       [
39245         "Palestine (‫فلسطين‬‎)",
39246         "ps",
39247         "970"
39248       ],
39249       [
39250         "Panama (Panamá)",
39251         "pa",
39252         "507"
39253       ],
39254       [
39255         "Papua New Guinea",
39256         "pg",
39257         "675"
39258       ],
39259       [
39260         "Paraguay",
39261         "py",
39262         "595"
39263       ],
39264       [
39265         "Peru (Perú)",
39266         "pe",
39267         "51"
39268       ],
39269       [
39270         "Philippines",
39271         "ph",
39272         "63"
39273       ],
39274       [
39275         "Poland (Polska)",
39276         "pl",
39277         "48"
39278       ],
39279       [
39280         "Portugal",
39281         "pt",
39282         "351"
39283       ],
39284       [
39285         "Puerto Rico",
39286         "pr",
39287         "1",
39288         3,
39289         ["787", "939"]
39290       ],
39291       [
39292         "Qatar (‫قطر‬‎)",
39293         "qa",
39294         "974"
39295       ],
39296       [
39297         "Réunion (La Réunion)",
39298         "re",
39299         "262",
39300         0
39301       ],
39302       [
39303         "Romania (România)",
39304         "ro",
39305         "40"
39306       ],
39307       [
39308         "Russia (Россия)",
39309         "ru",
39310         "7",
39311         0
39312       ],
39313       [
39314         "Rwanda",
39315         "rw",
39316         "250"
39317       ],
39318       [
39319         "Saint Barthélemy",
39320         "bl",
39321         "590",
39322         1
39323       ],
39324       [
39325         "Saint Helena",
39326         "sh",
39327         "290"
39328       ],
39329       [
39330         "Saint Kitts and Nevis",
39331         "kn",
39332         "1869"
39333       ],
39334       [
39335         "Saint Lucia",
39336         "lc",
39337         "1758"
39338       ],
39339       [
39340         "Saint Martin (Saint-Martin (partie française))",
39341         "mf",
39342         "590",
39343         2
39344       ],
39345       [
39346         "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39347         "pm",
39348         "508"
39349       ],
39350       [
39351         "Saint Vincent and the Grenadines",
39352         "vc",
39353         "1784"
39354       ],
39355       [
39356         "Samoa",
39357         "ws",
39358         "685"
39359       ],
39360       [
39361         "San Marino",
39362         "sm",
39363         "378"
39364       ],
39365       [
39366         "São Tomé and Príncipe (São Tomé e Príncipe)",
39367         "st",
39368         "239"
39369       ],
39370       [
39371         "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
39372         "sa",
39373         "966"
39374       ],
39375       [
39376         "Senegal (Sénégal)",
39377         "sn",
39378         "221"
39379       ],
39380       [
39381         "Serbia (Србија)",
39382         "rs",
39383         "381"
39384       ],
39385       [
39386         "Seychelles",
39387         "sc",
39388         "248"
39389       ],
39390       [
39391         "Sierra Leone",
39392         "sl",
39393         "232"
39394       ],
39395       [
39396         "Singapore",
39397         "sg",
39398         "65"
39399       ],
39400       [
39401         "Sint Maarten",
39402         "sx",
39403         "1721"
39404       ],
39405       [
39406         "Slovakia (Slovensko)",
39407         "sk",
39408         "421"
39409       ],
39410       [
39411         "Slovenia (Slovenija)",
39412         "si",
39413         "386"
39414       ],
39415       [
39416         "Solomon Islands",
39417         "sb",
39418         "677"
39419       ],
39420       [
39421         "Somalia (Soomaaliya)",
39422         "so",
39423         "252"
39424       ],
39425       [
39426         "South Africa",
39427         "za",
39428         "27"
39429       ],
39430       [
39431         "South Korea (대한민국)",
39432         "kr",
39433         "82"
39434       ],
39435       [
39436         "South Sudan (‫جنوب السودان‬‎)",
39437         "ss",
39438         "211"
39439       ],
39440       [
39441         "Spain (España)",
39442         "es",
39443         "34"
39444       ],
39445       [
39446         "Sri Lanka (ශ්‍රී ලංකාව)",
39447         "lk",
39448         "94"
39449       ],
39450       [
39451         "Sudan (‫السودان‬‎)",
39452         "sd",
39453         "249"
39454       ],
39455       [
39456         "Suriname",
39457         "sr",
39458         "597"
39459       ],
39460       [
39461         "Svalbard and Jan Mayen",
39462         "sj",
39463         "47",
39464         1
39465       ],
39466       [
39467         "Swaziland",
39468         "sz",
39469         "268"
39470       ],
39471       [
39472         "Sweden (Sverige)",
39473         "se",
39474         "46"
39475       ],
39476       [
39477         "Switzerland (Schweiz)",
39478         "ch",
39479         "41"
39480       ],
39481       [
39482         "Syria (‫سوريا‬‎)",
39483         "sy",
39484         "963"
39485       ],
39486       [
39487         "Taiwan (台灣)",
39488         "tw",
39489         "886"
39490       ],
39491       [
39492         "Tajikistan",
39493         "tj",
39494         "992"
39495       ],
39496       [
39497         "Tanzania",
39498         "tz",
39499         "255"
39500       ],
39501       [
39502         "Thailand (ไทย)",
39503         "th",
39504         "66"
39505       ],
39506       [
39507         "Timor-Leste",
39508         "tl",
39509         "670"
39510       ],
39511       [
39512         "Togo",
39513         "tg",
39514         "228"
39515       ],
39516       [
39517         "Tokelau",
39518         "tk",
39519         "690"
39520       ],
39521       [
39522         "Tonga",
39523         "to",
39524         "676"
39525       ],
39526       [
39527         "Trinidad and Tobago",
39528         "tt",
39529         "1868"
39530       ],
39531       [
39532         "Tunisia (‫تونس‬‎)",
39533         "tn",
39534         "216"
39535       ],
39536       [
39537         "Turkey (Türkiye)",
39538         "tr",
39539         "90"
39540       ],
39541       [
39542         "Turkmenistan",
39543         "tm",
39544         "993"
39545       ],
39546       [
39547         "Turks and Caicos Islands",
39548         "tc",
39549         "1649"
39550       ],
39551       [
39552         "Tuvalu",
39553         "tv",
39554         "688"
39555       ],
39556       [
39557         "U.S. Virgin Islands",
39558         "vi",
39559         "1340"
39560       ],
39561       [
39562         "Uganda",
39563         "ug",
39564         "256"
39565       ],
39566       [
39567         "Ukraine (Україна)",
39568         "ua",
39569         "380"
39570       ],
39571       [
39572         "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)",
39573         "ae",
39574         "971"
39575       ],
39576       [
39577         "United Kingdom",
39578         "gb",
39579         "44",
39580         0
39581       ],
39582       [
39583         "United States",
39584         "us",
39585         "1",
39586         0
39587       ],
39588       [
39589         "Uruguay",
39590         "uy",
39591         "598"
39592       ],
39593       [
39594         "Uzbekistan (Oʻzbekiston)",
39595         "uz",
39596         "998"
39597       ],
39598       [
39599         "Vanuatu",
39600         "vu",
39601         "678"
39602       ],
39603       [
39604         "Vatican City (Città del Vaticano)",
39605         "va",
39606         "39",
39607         1
39608       ],
39609       [
39610         "Venezuela",
39611         "ve",
39612         "58"
39613       ],
39614       [
39615         "Vietnam (Việt Nam)",
39616         "vn",
39617         "84"
39618       ],
39619       [
39620         "Wallis and Futuna (Wallis-et-Futuna)",
39621         "wf",
39622         "681"
39623       ],
39624       [
39625         "Western Sahara (‫الصحراء الغربية‬‎)",
39626         "eh",
39627         "212",
39628         1
39629       ],
39630       [
39631         "Yemen (‫اليمن‬‎)",
39632         "ye",
39633         "967"
39634       ],
39635       [
39636         "Zambia",
39637         "zm",
39638         "260"
39639       ],
39640       [
39641         "Zimbabwe",
39642         "zw",
39643         "263"
39644       ],
39645       [
39646         "Åland Islands",
39647         "ax",
39648         "358",
39649         1
39650       ]
39651   ];
39652   
39653   return d;
39654 }/**
39655 *    This script refer to:
39656 *    Title: International Telephone Input
39657 *    Author: Jack O'Connor
39658 *    Code version:  v12.1.12
39659 *    Availability: https://github.com/jackocnr/intl-tel-input.git
39660 **/
39661
39662 /**
39663  * @class Roo.bootstrap.PhoneInput
39664  * @extends Roo.bootstrap.TriggerField
39665  * An input with International dial-code selection
39666  
39667  * @cfg {String} defaultDialCode default '+852'
39668  * @cfg {Array} preferedCountries default []
39669   
39670  * @constructor
39671  * Create a new PhoneInput.
39672  * @param {Object} config Configuration options
39673  */
39674
39675 Roo.bootstrap.PhoneInput = function(config) {
39676     Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39677 };
39678
39679 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39680         
39681         listWidth: undefined,
39682         
39683         selectedClass: 'active',
39684         
39685         invalidClass : "has-warning",
39686         
39687         validClass: 'has-success',
39688         
39689         allowed: '0123456789',
39690         
39691         /**
39692          * @cfg {String} defaultDialCode The default dial code when initializing the input
39693          */
39694         defaultDialCode: '+852',
39695         
39696         /**
39697          * @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
39698          */
39699         preferedCountries: false,
39700         
39701         getAutoCreate : function()
39702         {
39703             var data = Roo.bootstrap.PhoneInputData();
39704             var align = this.labelAlign || this.parentLabelAlign();
39705             var id = Roo.id();
39706             
39707             this.allCountries = [];
39708             this.dialCodeMapping = [];
39709             
39710             for (var i = 0; i < data.length; i++) {
39711               var c = data[i];
39712               this.allCountries[i] = {
39713                 name: c[0],
39714                 iso2: c[1],
39715                 dialCode: c[2],
39716                 priority: c[3] || 0,
39717                 areaCodes: c[4] || null
39718               };
39719               this.dialCodeMapping[c[2]] = {
39720                   name: c[0],
39721                   iso2: c[1],
39722                   priority: c[3] || 0,
39723                   areaCodes: c[4] || null
39724               };
39725             }
39726             
39727             var cfg = {
39728                 cls: 'form-group',
39729                 cn: []
39730             };
39731             
39732             var input =  {
39733                 tag: 'input',
39734                 id : id,
39735                 cls : 'form-control tel-input',
39736                 autocomplete: 'new-password'
39737             };
39738             
39739             var hiddenInput = {
39740                 tag: 'input',
39741                 type: 'hidden',
39742                 cls: 'hidden-tel-input'
39743             };
39744             
39745             if (this.name) {
39746                 hiddenInput.name = this.name;
39747             }
39748             
39749             if (this.disabled) {
39750                 input.disabled = true;
39751             }
39752             
39753             var flag_container = {
39754                 tag: 'div',
39755                 cls: 'flag-box',
39756                 cn: [
39757                     {
39758                         tag: 'div',
39759                         cls: 'flag'
39760                     },
39761                     {
39762                         tag: 'div',
39763                         cls: 'caret'
39764                     }
39765                 ]
39766             };
39767             
39768             var box = {
39769                 tag: 'div',
39770                 cls: this.hasFeedback ? 'has-feedback' : '',
39771                 cn: [
39772                     hiddenInput,
39773                     input,
39774                     {
39775                         tag: 'input',
39776                         cls: 'dial-code-holder',
39777                         disabled: true
39778                     }
39779                 ]
39780             };
39781             
39782             var container = {
39783                 cls: 'roo-select2-container input-group',
39784                 cn: [
39785                     flag_container,
39786                     box
39787                 ]
39788             };
39789             
39790             if (this.fieldLabel.length) {
39791                 var indicator = {
39792                     tag: 'i',
39793                     tooltip: 'This field is required'
39794                 };
39795                 
39796                 var label = {
39797                     tag: 'label',
39798                     'for':  id,
39799                     cls: 'control-label',
39800                     cn: []
39801                 };
39802                 
39803                 var label_text = {
39804                     tag: 'span',
39805                     html: this.fieldLabel
39806                 };
39807                 
39808                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
39809                 label.cn = [
39810                     indicator,
39811                     label_text
39812                 ];
39813                 
39814                 if(this.indicatorpos == 'right') {
39815                     indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
39816                     label.cn = [
39817                         label_text,
39818                         indicator
39819                     ];
39820                 }
39821                 
39822                 if(align == 'left') {
39823                     container = {
39824                         tag: 'div',
39825                         cn: [
39826                             container
39827                         ]
39828                     };
39829                     
39830                     if(this.labelWidth > 12){
39831                         label.style = "width: " + this.labelWidth + 'px';
39832                     }
39833                     if(this.labelWidth < 13 && this.labelmd == 0){
39834                         this.labelmd = this.labelWidth;
39835                     }
39836                     if(this.labellg > 0){
39837                         label.cls += ' col-lg-' + this.labellg;
39838                         input.cls += ' col-lg-' + (12 - this.labellg);
39839                     }
39840                     if(this.labelmd > 0){
39841                         label.cls += ' col-md-' + this.labelmd;
39842                         container.cls += ' col-md-' + (12 - this.labelmd);
39843                     }
39844                     if(this.labelsm > 0){
39845                         label.cls += ' col-sm-' + this.labelsm;
39846                         container.cls += ' col-sm-' + (12 - this.labelsm);
39847                     }
39848                     if(this.labelxs > 0){
39849                         label.cls += ' col-xs-' + this.labelxs;
39850                         container.cls += ' col-xs-' + (12 - this.labelxs);
39851                     }
39852                 }
39853             }
39854             
39855             cfg.cn = [
39856                 label,
39857                 container
39858             ];
39859             
39860             var settings = this;
39861             
39862             ['xs','sm','md','lg'].map(function(size){
39863                 if (settings[size]) {
39864                     cfg.cls += ' col-' + size + '-' + settings[size];
39865                 }
39866             });
39867             
39868             this.store = new Roo.data.Store({
39869                 proxy : new Roo.data.MemoryProxy({}),
39870                 reader : new Roo.data.JsonReader({
39871                     fields : [
39872                         {
39873                             'name' : 'name',
39874                             'type' : 'string'
39875                         },
39876                         {
39877                             'name' : 'iso2',
39878                             'type' : 'string'
39879                         },
39880                         {
39881                             'name' : 'dialCode',
39882                             'type' : 'string'
39883                         },
39884                         {
39885                             'name' : 'priority',
39886                             'type' : 'string'
39887                         },
39888                         {
39889                             'name' : 'areaCodes',
39890                             'type' : 'string'
39891                         }
39892                     ]
39893                 })
39894             });
39895             
39896             if(!this.preferedCountries) {
39897                 this.preferedCountries = [
39898                     'hk',
39899                     'gb',
39900                     'us'
39901                 ];
39902             }
39903             
39904             var p = this.preferedCountries.reverse();
39905             
39906             if(p) {
39907                 for (var i = 0; i < p.length; i++) {
39908                     for (var j = 0; j < this.allCountries.length; j++) {
39909                         if(this.allCountries[j].iso2 == p[i]) {
39910                             var t = this.allCountries[j];
39911                             this.allCountries.splice(j,1);
39912                             this.allCountries.unshift(t);
39913                         }
39914                     } 
39915                 }
39916             }
39917             
39918             this.store.proxy.data = {
39919                 success: true,
39920                 data: this.allCountries
39921             };
39922             
39923             return cfg;
39924         },
39925         
39926         initEvents : function()
39927         {
39928             this.createList();
39929             Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
39930             
39931             this.indicator = this.indicatorEl();
39932             this.flag = this.flagEl();
39933             this.dialCodeHolder = this.dialCodeHolderEl();
39934             
39935             this.trigger = this.el.select('div.flag-box',true).first();
39936             this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39937             
39938             var _this = this;
39939             
39940             (function(){
39941                 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
39942                 _this.list.setWidth(lw);
39943             }).defer(100);
39944             
39945             this.list.on('mouseover', this.onViewOver, this);
39946             this.list.on('mousemove', this.onViewMove, this);
39947             this.inputEl().on("keyup", this.onKeyUp, this);
39948             
39949             this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
39950
39951             this.view = new Roo.View(this.list, this.tpl, {
39952                 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39953             });
39954             
39955             this.view.on('click', this.onViewClick, this);
39956             this.setValue(this.defaultDialCode);
39957         },
39958         
39959         onTriggerClick : function(e)
39960         {
39961             Roo.log('trigger click');
39962             if(this.disabled){
39963                 return;
39964             }
39965             
39966             if(this.isExpanded()){
39967                 this.collapse();
39968                 this.hasFocus = false;
39969             }else {
39970                 this.store.load({});
39971                 this.hasFocus = true;
39972                 this.expand();
39973             }
39974         },
39975         
39976         isExpanded : function()
39977         {
39978             return this.list.isVisible();
39979         },
39980         
39981         collapse : function()
39982         {
39983             if(!this.isExpanded()){
39984                 return;
39985             }
39986             this.list.hide();
39987             Roo.get(document).un('mousedown', this.collapseIf, this);
39988             Roo.get(document).un('mousewheel', this.collapseIf, this);
39989             this.fireEvent('collapse', this);
39990             this.validate();
39991         },
39992         
39993         expand : function()
39994         {
39995             Roo.log('expand');
39996
39997             if(this.isExpanded() || !this.hasFocus){
39998                 return;
39999             }
40000             
40001             var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40002             this.list.setWidth(lw);
40003             
40004             this.list.show();
40005             this.restrictHeight();
40006             
40007             Roo.get(document).on('mousedown', this.collapseIf, this);
40008             Roo.get(document).on('mousewheel', this.collapseIf, this);
40009             
40010             this.fireEvent('expand', this);
40011         },
40012         
40013         restrictHeight : function()
40014         {
40015             this.list.alignTo(this.inputEl(), this.listAlign);
40016             this.list.alignTo(this.inputEl(), this.listAlign);
40017         },
40018         
40019         onViewOver : function(e, t)
40020         {
40021             if(this.inKeyMode){
40022                 return;
40023             }
40024             var item = this.view.findItemFromChild(t);
40025             
40026             if(item){
40027                 var index = this.view.indexOf(item);
40028                 this.select(index, false);
40029             }
40030         },
40031
40032         // private
40033         onViewClick : function(view, doFocus, el, e)
40034         {
40035             var index = this.view.getSelectedIndexes()[0];
40036             
40037             var r = this.store.getAt(index);
40038             
40039             if(r){
40040                 this.onSelect(r, index);
40041             }
40042             if(doFocus !== false && !this.blockFocus){
40043                 this.inputEl().focus();
40044             }
40045         },
40046         
40047         onViewMove : function(e, t)
40048         {
40049             this.inKeyMode = false;
40050         },
40051         
40052         select : function(index, scrollIntoView)
40053         {
40054             this.selectedIndex = index;
40055             this.view.select(index);
40056             if(scrollIntoView !== false){
40057                 var el = this.view.getNode(index);
40058                 if(el){
40059                     this.list.scrollChildIntoView(el, false);
40060                 }
40061             }
40062         },
40063         
40064         createList : function()
40065         {
40066             this.list = Roo.get(document.body).createChild({
40067                 tag: 'ul',
40068                 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40069                 style: 'display:none'
40070             });
40071             
40072             this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40073         },
40074         
40075         collapseIf : function(e)
40076         {
40077             var in_combo  = e.within(this.el);
40078             var in_list =  e.within(this.list);
40079             var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40080             
40081             if (in_combo || in_list || is_list) {
40082                 return;
40083             }
40084             this.collapse();
40085         },
40086         
40087         onSelect : function(record, index)
40088         {
40089             if(this.fireEvent('beforeselect', this, record, index) !== false){
40090                 
40091                 this.setFlagClass(record.data.iso2);
40092                 this.setDialCode(record.data.dialCode);
40093                 this.hasFocus = false;
40094                 this.collapse();
40095                 this.fireEvent('select', this, record, index);
40096             }
40097         },
40098         
40099         flagEl : function()
40100         {
40101             var flag = this.el.select('div.flag',true).first();
40102             if(!flag){
40103                 return false;
40104             }
40105             return flag;
40106         },
40107         
40108         dialCodeHolderEl : function()
40109         {
40110             var d = this.el.select('input.dial-code-holder',true).first();
40111             if(!d){
40112                 return false;
40113             }
40114             return d;
40115         },
40116         
40117         setDialCode : function(v)
40118         {
40119             this.dialCodeHolder.dom.value = '+'+v;
40120         },
40121         
40122         setFlagClass : function(n)
40123         {
40124             this.flag.dom.className = 'flag '+n;
40125         },
40126         
40127         getValue : function()
40128         {
40129             var v = this.inputEl().getValue();
40130             if(this.dialCodeHolder) {
40131                 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40132             }
40133             return v;
40134         },
40135         
40136         setValue : function(v)
40137         {
40138             var d = this.getDialCode(v);
40139             
40140             //invalid dial code
40141             if(v.length == 0 || !d || d.length == 0) {
40142                 if(this.rendered){
40143                     this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40144                     this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40145                 }
40146                 return;
40147             }
40148             
40149             //valid dial code
40150             this.setFlagClass(this.dialCodeMapping[d].iso2);
40151             this.setDialCode(d);
40152             this.inputEl().dom.value = v.replace('+'+d,'');
40153             this.hiddenEl().dom.value = this.getValue();
40154             
40155             this.validate();
40156         },
40157         
40158         getDialCode : function(v)
40159         {
40160             v = v ||  '';
40161             
40162             if (v.length == 0) {
40163                 return this.dialCodeHolder.dom.value;
40164             }
40165             
40166             var dialCode = "";
40167             if (v.charAt(0) != "+") {
40168                 return false;
40169             }
40170             var numericChars = "";
40171             for (var i = 1; i < v.length; i++) {
40172               var c = v.charAt(i);
40173               if (!isNaN(c)) {
40174                 numericChars += c;
40175                 if (this.dialCodeMapping[numericChars]) {
40176                   dialCode = v.substr(1, i);
40177                 }
40178                 if (numericChars.length == 4) {
40179                   break;
40180                 }
40181               }
40182             }
40183             return dialCode;
40184         },
40185         
40186         reset : function()
40187         {
40188             this.setValue(this.defaultDialCode);
40189             this.validate();
40190         },
40191         
40192         hiddenEl : function()
40193         {
40194             return this.el.select('input.hidden-tel-input',true).first();
40195         },
40196         
40197         onKeyUp : function(e){
40198             
40199             var k = e.getKey();
40200             var c = e.getCharCode();
40201             
40202             if(
40203                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40204                     this.allowed.indexOf(String.fromCharCode(c)) === -1
40205             ){
40206                 e.stopEvent();
40207             }
40208             
40209             // if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40210             //     return;
40211             // }
40212             if(this.allowed.indexOf(String.fromCharCode(c)) === -1){
40213                 e.stopEvent();
40214             }
40215             
40216             this.setValue(this.getValue());
40217         }
40218         
40219 });
40220 /**
40221  * @class Roo.bootstrap.MoneyField
40222  * @extends Roo.bootstrap.ComboBox
40223  * Bootstrap MoneyField class
40224  * 
40225  * @constructor
40226  * Create a new MoneyField.
40227  * @param {Object} config Configuration options
40228  */
40229
40230 Roo.bootstrap.MoneyField = function(config) {
40231     
40232     Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40233     
40234 };
40235
40236 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40237     
40238     /**
40239      * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40240      */
40241     allowDecimals : true,
40242     /**
40243      * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40244      */
40245     decimalSeparator : ".",
40246     /**
40247      * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40248      */
40249     decimalPrecision : 0,
40250     /**
40251      * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40252      */
40253     allowNegative : true,
40254     /**
40255      * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40256      */
40257     allowZero: true,
40258     /**
40259      * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40260      */
40261     minValue : Number.NEGATIVE_INFINITY,
40262     /**
40263      * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40264      */
40265     maxValue : Number.MAX_VALUE,
40266     /**
40267      * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40268      */
40269     minText : "The minimum value for this field is {0}",
40270     /**
40271      * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40272      */
40273     maxText : "The maximum value for this field is {0}",
40274     /**
40275      * @cfg {String} nanText Error text to display if the value is not a valid number.  For example, this can happen
40276      * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40277      */
40278     nanText : "{0} is not a valid number",
40279     /**
40280      * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40281      */
40282     castInt : true,
40283     /**
40284      * @cfg {String} defaults currency of the MoneyField
40285      * value should be in lkey
40286      */
40287     defaultCurrency : false,
40288     /**
40289      * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40290      */
40291     thousandsDelimiter : false,
40292     
40293     
40294     inputlg : 9,
40295     inputmd : 9,
40296     inputsm : 9,
40297     inputxs : 6,
40298     
40299     store : false,
40300     
40301     getAutoCreate : function()
40302     {
40303         var align = this.labelAlign || this.parentLabelAlign();
40304         
40305         var id = Roo.id();
40306
40307         var cfg = {
40308             cls: 'form-group',
40309             cn: []
40310         };
40311
40312         var input =  {
40313             tag: 'input',
40314             id : id,
40315             cls : 'form-control roo-money-amount-input',
40316             autocomplete: 'new-password'
40317         };
40318         
40319         var hiddenInput = {
40320             tag: 'input',
40321             type: 'hidden',
40322             id: Roo.id(),
40323             cls: 'hidden-number-input'
40324         };
40325         
40326         if (this.name) {
40327             hiddenInput.name = this.name;
40328         }
40329
40330         if (this.disabled) {
40331             input.disabled = true;
40332         }
40333
40334         var clg = 12 - this.inputlg;
40335         var cmd = 12 - this.inputmd;
40336         var csm = 12 - this.inputsm;
40337         var cxs = 12 - this.inputxs;
40338         
40339         var container = {
40340             tag : 'div',
40341             cls : 'row roo-money-field',
40342             cn : [
40343                 {
40344                     tag : 'div',
40345                     cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40346                     cn : [
40347                         {
40348                             tag : 'div',
40349                             cls: 'roo-select2-container input-group',
40350                             cn: [
40351                                 {
40352                                     tag : 'input',
40353                                     cls : 'form-control roo-money-currency-input',
40354                                     autocomplete: 'new-password',
40355                                     readOnly : 1,
40356                                     name : this.currencyName
40357                                 },
40358                                 {
40359                                     tag :'span',
40360                                     cls : 'input-group-addon',
40361                                     cn : [
40362                                         {
40363                                             tag: 'span',
40364                                             cls: 'caret'
40365                                         }
40366                                     ]
40367                                 }
40368                             ]
40369                         }
40370                     ]
40371                 },
40372                 {
40373                     tag : 'div',
40374                     cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40375                     cn : [
40376                         {
40377                             tag: 'div',
40378                             cls: this.hasFeedback ? 'has-feedback' : '',
40379                             cn: [
40380                                 input
40381                             ]
40382                         }
40383                     ]
40384                 }
40385             ]
40386             
40387         };
40388         
40389         if (this.fieldLabel.length) {
40390             var indicator = {
40391                 tag: 'i',
40392                 tooltip: 'This field is required'
40393             };
40394
40395             var label = {
40396                 tag: 'label',
40397                 'for':  id,
40398                 cls: 'control-label',
40399                 cn: []
40400             };
40401
40402             var label_text = {
40403                 tag: 'span',
40404                 html: this.fieldLabel
40405             };
40406
40407             indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40408             label.cn = [
40409                 indicator,
40410                 label_text
40411             ];
40412
40413             if(this.indicatorpos == 'right') {
40414                 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40415                 label.cn = [
40416                     label_text,
40417                     indicator
40418                 ];
40419             }
40420
40421             if(align == 'left') {
40422                 container = {
40423                     tag: 'div',
40424                     cn: [
40425                         container
40426                     ]
40427                 };
40428
40429                 if(this.labelWidth > 12){
40430                     label.style = "width: " + this.labelWidth + 'px';
40431                 }
40432                 if(this.labelWidth < 13 && this.labelmd == 0){
40433                     this.labelmd = this.labelWidth;
40434                 }
40435                 if(this.labellg > 0){
40436                     label.cls += ' col-lg-' + this.labellg;
40437                     input.cls += ' col-lg-' + (12 - this.labellg);
40438                 }
40439                 if(this.labelmd > 0){
40440                     label.cls += ' col-md-' + this.labelmd;
40441                     container.cls += ' col-md-' + (12 - this.labelmd);
40442                 }
40443                 if(this.labelsm > 0){
40444                     label.cls += ' col-sm-' + this.labelsm;
40445                     container.cls += ' col-sm-' + (12 - this.labelsm);
40446                 }
40447                 if(this.labelxs > 0){
40448                     label.cls += ' col-xs-' + this.labelxs;
40449                     container.cls += ' col-xs-' + (12 - this.labelxs);
40450                 }
40451             }
40452         }
40453
40454         cfg.cn = [
40455             label,
40456             container,
40457             hiddenInput
40458         ];
40459         
40460         var settings = this;
40461
40462         ['xs','sm','md','lg'].map(function(size){
40463             if (settings[size]) {
40464                 cfg.cls += ' col-' + size + '-' + settings[size];
40465             }
40466         });
40467         
40468         return cfg;
40469     },
40470     
40471     initEvents : function()
40472     {
40473         this.indicator = this.indicatorEl();
40474         
40475         this.initCurrencyEvent();
40476         
40477         this.initNumberEvent();
40478     },
40479     
40480     initCurrencyEvent : function()
40481     {
40482         if (!this.store) {
40483             throw "can not find store for combo";
40484         }
40485         
40486         this.store = Roo.factory(this.store, Roo.data);
40487         this.store.parent = this;
40488         
40489         this.createList();
40490         
40491         this.triggerEl = this.el.select('.input-group-addon', true).first();
40492         
40493         this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40494         
40495         var _this = this;
40496         
40497         (function(){
40498             var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40499             _this.list.setWidth(lw);
40500         }).defer(100);
40501         
40502         this.list.on('mouseover', this.onViewOver, this);
40503         this.list.on('mousemove', this.onViewMove, this);
40504         this.list.on('scroll', this.onViewScroll, this);
40505         
40506         if(!this.tpl){
40507             this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40508         }
40509         
40510         this.view = new Roo.View(this.list, this.tpl, {
40511             singleSelect:true, store: this.store, selectedClass: this.selectedClass
40512         });
40513         
40514         this.view.on('click', this.onViewClick, this);
40515         
40516         this.store.on('beforeload', this.onBeforeLoad, this);
40517         this.store.on('load', this.onLoad, this);
40518         this.store.on('loadexception', this.onLoadException, this);
40519         
40520         this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40521             "up" : function(e){
40522                 this.inKeyMode = true;
40523                 this.selectPrev();
40524             },
40525
40526             "down" : function(e){
40527                 if(!this.isExpanded()){
40528                     this.onTriggerClick();
40529                 }else{
40530                     this.inKeyMode = true;
40531                     this.selectNext();
40532                 }
40533             },
40534
40535             "enter" : function(e){
40536                 this.collapse();
40537                 
40538                 if(this.fireEvent("specialkey", this, e)){
40539                     this.onViewClick(false);
40540                 }
40541                 
40542                 return true;
40543             },
40544
40545             "esc" : function(e){
40546                 this.collapse();
40547             },
40548
40549             "tab" : function(e){
40550                 this.collapse();
40551                 
40552                 if(this.fireEvent("specialkey", this, e)){
40553                     this.onViewClick(false);
40554                 }
40555                 
40556                 return true;
40557             },
40558
40559             scope : this,
40560
40561             doRelay : function(foo, bar, hname){
40562                 if(hname == 'down' || this.scope.isExpanded()){
40563                    return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40564                 }
40565                 return true;
40566             },
40567
40568             forceKeyDown: true
40569         });
40570         
40571         this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40572         
40573     },
40574     
40575     initNumberEvent : function(e)
40576     {
40577         this.inputEl().on("keydown" , this.fireKey,  this);
40578         this.inputEl().on("focus", this.onFocus,  this);
40579         this.inputEl().on("blur", this.onBlur,  this);
40580         
40581         this.inputEl().relayEvent('keyup', this);
40582         
40583         if(this.indicator){
40584             this.indicator.addClass('invisible');
40585         }
40586  
40587         this.originalValue = this.getValue();
40588         
40589         if(this.validationEvent == 'keyup'){
40590             this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40591             this.inputEl().on('keyup', this.filterValidation, this);
40592         }
40593         else if(this.validationEvent !== false){
40594             this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40595         }
40596         
40597         if(this.selectOnFocus){
40598             this.on("focus", this.preFocus, this);
40599             
40600         }
40601         if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40602             this.inputEl().on("keypress", this.filterKeys, this);
40603         } else {
40604             this.inputEl().relayEvent('keypress', this);
40605         }
40606         
40607         var allowed = "0123456789";
40608         
40609         if(this.allowDecimals){
40610             allowed += this.decimalSeparator;
40611         }
40612         
40613         if(this.allowNegative){
40614             allowed += "-";
40615         }
40616         
40617         if(this.thousandsDelimiter) {
40618             allowed += ",";
40619         }
40620         
40621         this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40622         
40623         var keyPress = function(e){
40624             
40625             var k = e.getKey();
40626             
40627             var c = e.getCharCode();
40628             
40629             if(
40630                     (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40631                     allowed.indexOf(String.fromCharCode(c)) === -1
40632             ){
40633                 e.stopEvent();
40634                 return;
40635             }
40636             
40637             if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40638                 return;
40639             }
40640             
40641             if(allowed.indexOf(String.fromCharCode(c)) === -1){
40642                 e.stopEvent();
40643             }
40644         };
40645         
40646         this.inputEl().on("keypress", keyPress, this);
40647         
40648     },
40649     
40650     onTriggerClick : function(e)
40651     {   
40652         if(this.disabled){
40653             return;
40654         }
40655         
40656         this.page = 0;
40657         this.loadNext = false;
40658         
40659         if(this.isExpanded()){
40660             this.collapse();
40661             return;
40662         }
40663         
40664         this.hasFocus = true;
40665         
40666         if(this.triggerAction == 'all') {
40667             this.doQuery(this.allQuery, true);
40668             return;
40669         }
40670         
40671         this.doQuery(this.getRawValue());
40672     },
40673     
40674     getCurrency : function()
40675     {   
40676         var v = this.currencyEl().getValue();
40677         
40678         return v;
40679     },
40680     
40681     restrictHeight : function()
40682     {
40683         this.list.alignTo(this.currencyEl(), this.listAlign);
40684         this.list.alignTo(this.currencyEl(), this.listAlign);
40685     },
40686     
40687     onViewClick : function(view, doFocus, el, e)
40688     {
40689         var index = this.view.getSelectedIndexes()[0];
40690         
40691         var r = this.store.getAt(index);
40692         
40693         if(r){
40694             this.onSelect(r, index);
40695         }
40696     },
40697     
40698     onSelect : function(record, index){
40699         
40700         if(this.fireEvent('beforeselect', this, record, index) !== false){
40701         
40702             this.setFromCurrencyData(index > -1 ? record.data : false);
40703             
40704             this.collapse();
40705             
40706             this.fireEvent('select', this, record, index);
40707         }
40708     },
40709     
40710     setFromCurrencyData : function(o)
40711     {
40712         var currency = '';
40713         
40714         this.lastCurrency = o;
40715         
40716         if (this.currencyField) {
40717             currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40718         } else {
40719             Roo.log('no  currencyField value set for '+ (this.name ? this.name : this.id));
40720         }
40721         
40722         this.lastSelectionText = currency;
40723         
40724         //setting default currency
40725         if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
40726             this.setCurrency(this.defaultCurrency);
40727             return;
40728         }
40729         
40730         this.setCurrency(currency);
40731     },
40732     
40733     setFromData : function(o)
40734     {
40735         var c = {};
40736         
40737         c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
40738         
40739         this.setFromCurrencyData(c);
40740         
40741         var value = '';
40742         
40743         if (this.name) {
40744             value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
40745         } else {
40746             Roo.log('no value set for '+ (this.name ? this.name : this.id));
40747         }
40748         
40749         this.setValue(value);
40750         
40751     },
40752     
40753     setCurrency : function(v)
40754     {   
40755         this.currencyValue = v;
40756         
40757         if(this.rendered){
40758             this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
40759             this.validate();
40760         }
40761     },
40762     
40763     setValue : function(v)
40764     {
40765         v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
40766         
40767         this.value = v;
40768         
40769         if(this.rendered){
40770             
40771             this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40772             
40773             this.inputEl().dom.value = (v == '') ? '' :
40774                 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
40775             
40776             if(!this.allowZero && v === '0') {
40777                 this.hiddenEl().dom.value = '';
40778                 this.inputEl().dom.value = '';
40779             }
40780             
40781             this.validate();
40782         }
40783     },
40784     
40785     getRawValue : function()
40786     {
40787         var v = this.inputEl().getValue();
40788         
40789         return v;
40790     },
40791     
40792     getValue : function()
40793     {
40794         return this.fixPrecision(this.parseValue(this.getRawValue()));
40795     },
40796     
40797     parseValue : function(value)
40798     {
40799         if(this.thousandsDelimiter) {
40800             value += "";
40801             r = new RegExp(",", "g");
40802             value = value.replace(r, "");
40803         }
40804         
40805         value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40806         return isNaN(value) ? '' : value;
40807         
40808     },
40809     
40810     fixPrecision : function(value)
40811     {
40812         if(this.thousandsDelimiter) {
40813             value += "";
40814             r = new RegExp(",", "g");
40815             value = value.replace(r, "");
40816         }
40817         
40818         var nan = isNaN(value);
40819         
40820         if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40821             return nan ? '' : value;
40822         }
40823         return parseFloat(value).toFixed(this.decimalPrecision);
40824     },
40825     
40826     decimalPrecisionFcn : function(v)
40827     {
40828         return Math.floor(v);
40829     },
40830     
40831     validateValue : function(value)
40832     {
40833         if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
40834             return false;
40835         }
40836         
40837         var num = this.parseValue(value);
40838         
40839         if(isNaN(num)){
40840             this.markInvalid(String.format(this.nanText, value));
40841             return false;
40842         }
40843         
40844         if(num < this.minValue){
40845             this.markInvalid(String.format(this.minText, this.minValue));
40846             return false;
40847         }
40848         
40849         if(num > this.maxValue){
40850             this.markInvalid(String.format(this.maxText, this.maxValue));
40851             return false;
40852         }
40853         
40854         return true;
40855     },
40856     
40857     validate : function()
40858     {
40859         if(this.disabled || this.allowBlank){
40860             this.markValid();
40861             return true;
40862         }
40863         
40864         var currency = this.getCurrency();
40865         
40866         if(this.validateValue(this.getRawValue()) && currency.length){
40867             this.markValid();
40868             return true;
40869         }
40870         
40871         this.markInvalid();
40872         return false;
40873     },
40874     
40875     getName: function()
40876     {
40877         return this.name;
40878     },
40879     
40880     beforeBlur : function()
40881     {
40882         if(!this.castInt){
40883             return;
40884         }
40885         
40886         var v = this.parseValue(this.getRawValue());
40887         
40888         if(v || v == 0){
40889             this.setValue(v);
40890         }
40891     },
40892     
40893     onBlur : function()
40894     {
40895         this.beforeBlur();
40896         
40897         if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40898             //this.el.removeClass(this.focusClass);
40899         }
40900         
40901         this.hasFocus = false;
40902         
40903         if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40904             this.validate();
40905         }
40906         
40907         var v = this.getValue();
40908         
40909         if(String(v) !== String(this.startValue)){
40910             this.fireEvent('change', this, v, this.startValue);
40911         }
40912         
40913         this.fireEvent("blur", this);
40914     },
40915     
40916     inputEl : function()
40917     {
40918         return this.el.select('.roo-money-amount-input', true).first();
40919     },
40920     
40921     currencyEl : function()
40922     {
40923         return this.el.select('.roo-money-currency-input', true).first();
40924     },
40925     
40926     hiddenEl : function()
40927     {
40928         return this.el.select('input.hidden-number-input',true).first();
40929     }
40930     
40931 });